gopls version

N/A

go env

N/A

What did you do?

N/A

What did you see happen?

N/A

What did you expect to see?

But these operators are not commonly used, we can find code that are doing things like that

  • strings.Split(s, sep)[0] : 140k
  • strings.Split(s, sep)[1]: 58k
  • strings.SplitN(s, sep, 2)[0] 23k
  • strings.SplitN(s, sep, 2)[1]: 8k

And all variations like, that are not as easy to spot with GitHub search.

    items := strings.Split(s, sep)
    before := items[0]
    items := strings.Split(s, sep)
    before := items[0]
    after := items[1]

I would like code to suggest using strings.Cut, as stated in the documentation of strings.Split

To split around the first instance of a separator, see Cut.

Also, strings.CutPrefix and strings.CutSuffix could be used.

Here are the

a := strings.Split(s, sep)[0]       // want a, _ := strings.CutSuffix(s, sep)
b := strings.Split(s, sep)[1]       // want b, _ := strings.CutPrefix(s, sep)
c := strings.SplitN(s, sep, 2)[0] // want c, _ := strings.CutSuffix(s, sep)
d : strings.SplitN(s, sep, 2)[1]   // want d, _ := strings.CutSuffix(s, sep)

And about this one, that can panic if the separator is not found.

items := strings.Split(s, sep)
before := items[0]
after := items[1]
before, after, _ := strings.Cut(s, sep)

Here I'm assuming items is not reused.

Please note there are code that do things like that

items := strings.Split(s, sep) // or SplitN(s, sep, 2)
if len(items) < 2 { // or len(items) == 1
    return errors.New("whatever")
}
before := items[0]
after := items[1]

or

items := strings.Split(s, sep) // or SplitN(s, sep, 2)
if len(items) == 2 { // or len(items) != 1
    doSomething(items[0], items[1])
}

They can be easily found among these results

Editor and settings

No response

Logs

No response

Comment From: ccoVeille

I opened it here as modernize already supports stringscutprefix and looked for existing issues.

This one is somehow close to what I describe here, but about strings.TrimPrefix, not strings.Split

  • https://github.com/golang/go/issues/71369

Comment From: gabyhelp

Related Issues

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)

Comment From: adonovan

Before working on this problem, it would be good to write a precise statement of the correctness requirements. In the past these kinds of modernizers have been fraught with bugs, but I think we can mitigate them in future with a little more clarity aforethought.

Comment From: ccoVeille

I'm unsure if you are asking me to provide more context and examples, or if you asks for other people to define what they would expect.

So, I will try to challenge myself in what I asked for:

These two are equivalent

a := strings.Split(s, sep)[0]
c := strings.SplitN(s, sep, 2)[0]
a, _ := strings.CutSuffix(s, sep)
c, _ := strings.CutSuffix(s, sep)

So here it could be considered as opinionated, some may say the _ makes it awkward.

So it might not worth it.

These are less optionated and could avoid hypothetical panic

b := strings.Split(s, sep)[1]
d := strings.SplitN(s, sep, 2)[1]

I feel like these one is part of the concept of modernizing tge syntax

items := strings.Split(s, sep)
before := items[0]
after := items[1]
before, after, _ := strings.Cut(s, sep)

I could say more, but as I'm unsure what you meant. I will wait for feedbacks, including yours @adonovan

Comment From: adonovan

Sorry for being unclear. I was calling upon whoever decides to implement this feature to start, here, with a clear prose description, here, of the correctness criteria. For example, it must address the possibility of words := strings.Split(s, sep); ...; use(words[0], words[1]) containing an intervening ... operation that mutates the array. And so on.