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 {

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{}
    fmt.Println(r.Width)  // this works
    for _, s := range allShapes {
        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 {

    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:


    You will get what you want.

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

    点赞 打赏 评论

相关推荐 更多相似问题