Go to: interface method call

I have two questions regarding the Go interface from the following code.

type Color interface { getColor() string setColor(string) } type Car struct { color string } func (c Car) getColor() string { return c.color } func (c Car) setColor(s string) { c.color = s } func main() { car := Car{"white"} col := Color(car) car = col.(Car) // L(1) car.setColor("yellow") fmt.Println(col) // L(2) fmt.Println(car) car.color = "black" fmt.Println(col) // L(3) fmt.Println(car) } 

Q1: Can I write L(1) as "car, _ := col.(Car)"?

Q2: L(2) prints white, not yellow.

Why? L(3) looks correctly printed in black.

Thanks.

+4
source share
2 answers

one:

No, you cannot say the car, _: = col. (Car). The reason for this is not entirely obvious. Here is a list of valid statements in L1:

 car,ok := col.(Car) car = col.(Car) car,_ = col.(Car) _,ok := col.(Car) 

": =" is a short form for the announcement / destination, since the car has already been declared in this area :: = will give you an error ("there is no new variable on the left side: ="). Entering "ok" there declares a new variable ("ok"), however the underscore / ignore pseudo-variable is not considered a new variable for the purpose of: =.

Change To be clear, you can put “ok” or an underscore here because type statements return both a type value and a boolean indicating whether the statement was successful. If we were talking about the general case of "_", and not about the question of the operator:: =: no, in the general case you cannot do something like

 a,_ := 5 

Since this operator returns only one value, and go will not let you ignore anything. (You will get the error: "assignment counter mismatch 2 = 1").

2:

In Go, methods can be pointers or values ​​/ base types. I believe that you find the following will work well:

 car.setColor("yellow") //... func (car Car) setColor(s string) { car.color = s fmt.Println(car.color) } 

In this code, it will print "yellow" correctly. This is because you pass the method receiver by value. In fact, it modifies the car — but a different car than you passed it to, a car that turns out to be a perfect copy of the car you called this method on. To fix this, you need a pointer receiver,

 func (car *Car) setColor(s string) { car.color = s } 

This will make the changes visible after the call, because you give the method the location where the car is located, and not just the data that it has. To be careful, there are several cases related to "reference types" (maps, slices, channels), where you can see side effects outside the non-pointer method, but these are exceptions to the rule.

Note that if you give this method a pointer receiver, variables of type Car will no longer implement the Color interface. Instead, the type that implements the interface is * Car (car pointer). In fact, since pointers are transparent in Go, this is true even if you leave getColor with a non-pointer, but it's usually best to create all methods for a type that implements an interface on either the pointer or the base type, rather than a mixture of both.

One note as you seem to be learning: there is nothing wrong with the beginning of setColor and getColor with lowercase letters. However, keep in mind that these methods will not be available outside of the fastest package you write. To be visible, they must begin with a letter at the top level.

+8
source

In order for setColor to mutate the Car object, you expect to have to pass a pointer, your code passed the Car value by value and changed the color of that value, and then quickly canceled that copy of the Car value when the method returns

Here is your example modified so that the interface is satisfied with a pointer to Car

 func (c *Car) getColor() string { return c.color } func (c *Car) setColor(s string) { c.color = s } 

The above links:

 &{yellow} &{yellow} &{black} &{black} 
+2
source

Source: https://habr.com/ru/post/1494415/


All Articles