1
votes

I am quite new to go, and quite confused about the receiver idea in Go. It is the exercise from A tour of Go.

Question body:

Remember the picture generator you wrote earlier? Let's write another one, but this time it will return an implementation of image.Image instead of a slice of data.

Define your own Image type, implement the necessary methods, and call pic.ShowImage.

Bounds should return a image.Rectangle, like image.Rect(0, 0, w, h).

ColorModel should return color.RGBAModel.

At should return a color; the value v in the last picture generator corresponds to color.RGBA{v, v, 255, 255} in this one.

Here is my code:

package main

import "golang.org/x/tour/pic"
import "image"
import "image/color"


type Image struct{}

func (img *Image) Bounds() image.Rectangle{
    w := 100
    h := 100
    return image.Rect(0,0,w,h)
}

func (img *Image) ColorModel() color.Model{
    return color.RGBAModel
}

func (img *Image) At(x int, y int) color.Color{
    return color.RGBA{uint8(x^y), uint8(y/2), 255,255}
}

func main() {
    m := Image{}
    pic.ShowImage(m)
}

And it will report a compile error:

command-line-arguments ./compile110.go:26: cannot use m (type Image) as type image.Image in argument to pic.ShowImage: Image does not implement image.Image (At method has pointer receiver)


My understanding is that for receivers of methods, it is alright to set them as either pointers or values. However, when I set all the "*Image" to "Image", the errors go away.

Can someone help me with this?


The answers provided below are sufficient for the question I raised. However, it seems that the pointer and value receivers thingy can be a bit more complicated.

From Effective Go:

The rule about pointers vs. values for receivers is that value methods can be invoked on pointers and values, but pointer methods can only be invoked on pointers. This rule arises because pointer methods can modify the receiver; invoking them on a value would cause the method to receive a copy of the value, so any modifications would be discarded. The language therefore disallows this mistake. There is a handy exception, though. When the value is addressable, the language takes care of the common case of invoking a pointer method on a value by inserting the address operator automatically.

Hope this will help some of you as well.

2
Why are you even giving these function receivers? You don't use them. I feel like you are trying to make an interface.kylieCatt
it is a requirement of the question. I suspect the pic.ShowImage() is calling these methods for the interface image.Xu Chen

2 Answers

4
votes

When you use interfaces in Go you need to make sure the instance you are using implements that interface. In the Go-Tour example problem, Image does not satisfy the image.Image interface, only &Image does.

As such you need to either change your method signatures to take value receivers which will make Image work, or pass &Image to the pic.ShowImage function since the pointer to Image does implement the interface.

2
votes

There are two ways you can go about fixing this.

one way is using

func main() {
    m := &Image{}
    pic.ShowImage(m)
}

the other way is using a constructor

func NewImage() *Image {
    return &Image{}
}

func main() {
    m := NewImage()
    pic.ShowImage(m)
}