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?
- strings.Cut was added in Go 1.18
- strings.CutPrefix and strings.CutSuffix were added in Go 1.20
But these operators are not commonly used, we can find code that are doing things like that
strings.Split(s, sep)[0]
: 140kstrings.Split(s, sep)[1]
: 58kstrings.SplitN(s, sep, 2)[0]
23kstrings.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
- x/tools/gopls/internal/analysis/modernize: use strings.Cut #71369
- bytes, strings: add Cut #46336 (closed)
- proposal: bytes, strings: add CutByte #67101
- strings: add CutPrefix and CutSuffix #42537 (closed)
(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.