Go: spec: I think a behavior of `...` operator looks strange

Created on 2 Aug 2017  路  12Comments  路  Source: golang/go

Please answer these questions before submitting your issue. Thanks!

What version of Go are you using (go version)?

go version go1.8.3 windows/amd64

What operating system and processor architecture are you using (go env)?

Don't mind.

What did you do?

type S string

func fn(s ...S) {}

func TestFn(t *testing.T) {
    fn(S(""), S(""))
    fn("", "")
    fn(S(""), "")

    fn([]S{S(""), S("")}...)
    fn([]string{"", ""}...)
}

What did you expect to see?

Everything should works well.

What did you see instead?

I got an error: cannot use []string literal (type []string) as type []S in argument to fn

image

Is it a reasonable behaviour? That's my derivation:

fn(T, T, T, ...) == fn(t, t, t, ...)
[]T... => T, T, T, ...
fn([]T...) => fn(T, T, T, ...) => fn(t, t, t, ...) => Accept!
FrozenDueToAge

Most helpful comment

The documentation supports this behavior.
https://golang.org/ref/spec#Passing_arguments_to_..._parameters

If the final argument is assignable to a slice type []T, it may be passed unchanged as the value for a ...T parameter if the argument is followed by .... In this case no new slice is created.

Values of type [][]string is not assignable to the type []S, so it fails.

Given func fn(args ...string) and list := []string{"", ""},
fn(list...) is not identical to fn(list[0], list[1]).
fn(list...) meansargs = list while fn(list[0], list[1]) means
args = make([]string, 2); args[0] = list[0]; args[1] = list[1].

@zhengxiaoyao0716
Please do not use rhetorical question. It's unfriendly.

All 12 comments

The way it works is useful: https://play.golang.org/p/QCZDykSKAY.

@cznic r u kid me? u think I don't know how to use it?

u think I don't know how to use it?

The title says "_behavior of ... operator looks strange!._". I've just presented an example in which I tried to show why it is important for ... to work the way it does.

Of course I know what to do, I don't need someone to teach me how to it work. What I need is, why it works like those, how it be designed to this style, and could it work better use different way.

S and string are not the same type. You can not use fn(string("")) either.

You'll have to cast your S to string manually.

@zegl try this please

package main

type S []string

func fn(s ...S) {}

func main() {
    fn(S{""}, S{""})
    fn([]string{""}, []string{""})
    fn(S{""}, []string(S{""}))

    fn([]S{S{""}, S{""}}...)
    // fn([][]string{[]string{""}, []string{""}}...)
}

The documentation supports this behavior.
https://golang.org/ref/spec#Passing_arguments_to_..._parameters

If the final argument is assignable to a slice type []T, it may be passed unchanged as the value for a ...T parameter if the argument is followed by .... In this case no new slice is created.

Values of type [][]string is not assignable to the type []S, so it fails.

Given func fn(args ...string) and list := []string{"", ""},
fn(list...) is not identical to fn(list[0], list[1]).
fn(list...) meansargs = list while fn(list[0], list[1]) means
args = make([]string, 2); args[0] = list[0]; args[1] = list[1].

@zhengxiaoyao0716
Please do not use rhetorical question. It's unfriendly.

Closing because this is working as documented.

If you want to discuss why it works this way, please use the golang-nuts mailing list. Thanks.

Please be polite to people who are just trying to help. Thanks.

@crvv well, thank for your remind, I don't known rhetorical question is unfriendly before.
In Chinese,
image
is normal tone.
And from Chinese rhetorical question translate to English by Google:
image
u see, there are no different...

@ianlancetaylor ok, That's really my fault.

But i don't think this is working as documented, at least not in https://golang.org/ref/spec#Passing_arguments_to_..._parameters

The key of this problem is, I think mistack that a string value can assigned to S directly.

type S string

func TestS(t *testing.T) {
    var s S
    s = ""
    var str = ""
    // I think mistack that a string value can assigned to S directly.
    // s = str
    fmt.Println(s)
}

I'm not a new learner, but i always forgot to use s = S(str) instead of s = str, so today it puzzled me.

@zegl But there are still some problem, i really can not use fn(string("")), but in another case tha type S []string, why could i use fn([]string(S{""}))?

The language spec, in the section you cite, says that given a function f(...S) and a call f(s...), that the slice s must be assignable to []S. In your example s is []string, and []string is not assignable to []S, so the code does not compile. So I believe I am correct in saying that this is working as documented.

@ianlancetaylor yes, i known that the slice s must be assignable to []S at the beginning, that's a grammatical mistake. i'm ask for help that why this happend, and I'm glad I got it. Thank you all and please forgive my willfulness.

Was this page helpful?
0 / 5 - 0 ratings