Reputation:
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
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) whereT
is a type name. The type denoted byT
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.
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
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