Why can't I access this field in the interface?

I am trying to better understand the interfaces and do not understand why s does not have a Width field. My example is here :

 package main import "fmt" type shapes interface { setWidth(float64) } type rect struct { Width float64 } func (r *rect) setWidth(w float64) { r.Width = w } var allShapes = map[string]shapes{ "rect": &rect{}, } func main() { r := &rect{} r.setWidth(5) fmt.Println(r.Width) // this works for _, s := range allShapes { s.setWidth(7) fmt.Println(s.Width) // why not??? } } 

Why r is wide but s not? The exact error I get is:

 s.Width undefined (type shapes has no field or method Width) 
+5
source share
2 answers
Interface

shapes implements *rect , but it is not a specific *rect type. It, like any interface, is a set of methods that allow any type that satisfies its passage, for example, to provide a temporary business card for him to climb the building.

For example, if there is a monkey (or for the fact that it stands, a dolphin) that can act and do everything that a person can in the Guo building, he can go through security and take the elevator. However, this does not make him genetically human.

Go is statically typed, which means that even two types with the same basic type cannot dynamically convert or force each other without type approval or consciously convert the type.

 var a int type myInt int var b myInt a = 2 b = 3 b = a // Error! cannot use a (type int) as type myInt in assignment. b = myInt(a) // This is ok. 

Introduce yourself to me for a second in this situation:

 type MyInt int type YourInt int type EveryInt interface { addableByInt(a int) bool } func (i MyInt) addableByInt(a int) bool { // whatever logic doesn't matter return true } func (i YourInt) addableByInt(a int) bool { // whatever logic doesn't matter return true } func main() { // Two guys want to pass as an int b := MyInt(7) c := YourInt(2) // Do everything an `EveryInt` requires // and disguise as one bi := EveryInt(b) ci := EveryInt(c) // Hey, look we're the same! That the closest // we can get to being an int! bi = ci // This is ok, we are EveryInt brotherhood fmt.Println(bi) // bi is now 2 // Now a real int comes along saying // "Hey, you two look like one of us!" var i int i = bi // Oops! bi has been made // ci runs away at this point } 

Now back to your scenerio - imagine *circle implements shapes :

 type circle struct { Radius float64 } func (c *circle) setWidth(w float64) { c.Radius = w } 

*circle is completely skipped as shapes , but it does not have the Width property, because it is not *rect . An interface cannot directly access a property of a base type, but can only do this through an implemented set of methods. Accessing a property in an interface requires a type statement, so the instance becomes a concrete type:

 var r *rect // Verify `s` is in fact a `*rect` under the hood if r, ok := s.(*rect); ok { fmt.Println(r.Width) } 

This is at the heart of why a statically typed language like Go is always faster than dynamically typed counterparts, which will almost always use some kind of reflection to dynamically control the type for you.

+4
source

s is a form interface executor, but in a for loop it is not typed as rect. If you execute a type statement to force it to be a specific type:

 s.(*rect).Width 

You will get what you want.

You need to be careful in mixing specific types and interfaces like this.

+2
source

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


All Articles