user4211028
user4211028

Reputation:

Go array for method

Can I use array and its pointer for Go methods?

I have the following code:

var array = [3]string{"A", "B", "C"}
type arrayTypePt *[3]string
func (m *arrayTypePt) change() { m[1] = "W" }
func main() {
    (arrayTypePt(&array)).changeArray4()
}

But this code: http://play.golang.org/p/mXDEhmA9wk

give me an error of:

invalid receiver type *arrayTypePt (arrayTypePt is a pointer type)
invalid operation: m[1] (type *arrayTypePt does not support indexing)
arrayTypePt(&array).changeArray4 undefined (type arrayTypePt has no field or method changeArray4)

I get the same error when I try this with slice. Why I cannot do this in method?

Upvotes: 0

Views: 2555

Answers (2)

icza
icza

Reputation: 417662

The receiver type of a method cannot be a pointer to a pointer, but that is what you wrote:

func (m *arrayTypePt) change() { m[1] = "W" }

arrayTypePt is already a pointer *[3]string. Quoting from the language specification:

[The receiver] type must be of the form T or *T (possibly using parentheses) where T is a type name. The type denoted by T is called the receiver base type; it must not be a pointer or interface type and it must be declared in the same package as the method.

Your 2nd error ("type *arrayTypePt does not support indexing") is also a result of this (m is a pointer to pointer, that's why you can't index it; if it would only be a pointer to array or slice, the pointer indirection would be automatic).

Your 3rd error is simply a typo, you declared a method named change() and not changeArray4().

So you should only name the non-pointer array type:

type arrayType [3]string

And you can declare your array using directly this type:

var array = arrayType{"A", "B", "C"}

And you can simply call its change() method:

array.change()

The address of the array will be taken automatically (because the change() method has a pointer receiver but the array variable itself is not a pointer).

Try it on the Go Playground.

Notes / Alternatives

If you would want your array variable to be explicitly [3]string, you could still make it work by converting it to arrayType, setting it to another variable, and change() can be called on this (because being a variable its address can be taken - while the address of a conversion like arrayType(arr) cannot):

arr2 := [3]string{"A", "B", "C"}
arr3 := arrayType(arr2)
arr3.change()

Or if you would declare your variable to be a pointer to type [3]string, you could save the required additional variable (which was only required so we were able to take its address):

arr4 := new([3]string)
*arr4 = [3]string{"A", "B", "C"}
((*arrayType)(arr4)).change()

Try these variants too on the Go Playground.

Upvotes: 7

sqweek
sqweek

Reputation: 1187

It works fine if you define the array/slice variable as the receiver type:

type arrayType [3]string
var array arrayType = [3]string{"A", "B", "C"}   # note "arrayType" here
func (m *arrayType) change() { m[1] = "W" }
func main() {
    array.change()
}

I'm not sure why the typecasting behaves like it does.

Upvotes: 0

Related Questions