du7999
2016-04-08 04:36
浏览 28
已采纳

为什么我不能在界面中访问此字段?

I am trying to understand interfaces better and am not understanding why s has no field Width. 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 does r have Width but s doesn't? The exact error I get is:

s.Width undefined (type shapes has no field or method Width)
  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

2条回答 默认 最新

  • dongyikong6207 2016-04-08 05:04
    已采纳

    shapes interface is what *rect implements, but it is not a concrete type *rect. It is, like any interface, a set of methods allowing any type satisfying it to pass, like giving a temporary visitor sticker to it to go up the building.

    For instance, if there is a monkey (or for what it's worth, a dolphin) who can act and do everything a human can, in Go's building, he can pass the guard and go up the elevator. However, that doesn't make him genetically human.

    Go is statically-typed, meaning even two types with the same underlying type cannot be dynamically converted or coerced to one another without a type assertion or consciously converting 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.
    

    Imagine with me for a second 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's 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 a *circle comes along implementing shapes:

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

    *circle is totally passable as shapes but it does not have Width property because it is not a *rect. An interface cannot access an underlying type's property directly, but can only do so through implemented method set. In order to access a property, a type assertion is need on the interface so that 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 core 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 handle type coercion dynamically for you.

    点赞 打赏 评论
  • duannian7116 2016-04-08 05:05

    s is a an implementer of the shapes interface, but in the for loop not typed as a rect. If you do a type assertion to force s be of the concrete type like so:

    s.(*rect).Width
    

    You will get what you want.

    You need to be careful about mixing concrete types and interfaces like that though.

    点赞 打赏 评论

相关推荐 更多相似问题