du7999 2016-04-08 04:36 采纳率: 100%
浏览 29
已采纳

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

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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 保护模式-系统加载-段寄存器