代码之家  ›  专栏  ›  技术社区  ›  Hieu Le

使用值或指针接收器实现Stringer接口[duplicate]

go
  •  1
  • Hieu Le  · 技术社区  · 6 年前

    我试着实施 Stringer 我的类型上的接口如下:

    package main
    
    import (
        "fmt"
    )
    
    type IPAddr [4]byte
    
    // TODO: Add a "String() string" method to IPAddr.
    func (o IPAddr) String() string {
        return fmt.Sprintf("%v.%v.%v.%v",  o[0], o[1], o[2], o[3])
    }
    
    func main() {
        hosts := map[string]IPAddr{
            "loopback":  {127, 0, 0, 1},
            "googleDNS": {8, 8, 8, 8},
        }
        for name, ip := range hosts {
            fmt.Printf("%v: %v\n", name, ip)
            fmt.Printf("%v\n",  ip.String())
        }
    }
    

    在上面的代码中,我使用了一个值接收器来实现 String() 方法。这个 Printf String

    输出:

    googleDNS: 8.8.8.8
    8.8.8.8
    loopback: 127.0.0.1
    127.0.0.1
    

    func (o *IPAddr) String() string {
        return fmt.Sprintf("%v.%v.%v.%v",  o[0], o[1], o[2], o[3])
    }
    

    更新代码的输出:

    loopback: [127 0 0 1]
    127.0.0.1
    googleDNS: [8 8 8 8]
    8.8.8.8
    

    这个 方法没有调用我的 不再是方法了。输出告诉我 打印F 类型的方法。然而,当我打电话时 ip.String() ,使用了我的方法。

    非常感谢。

    2 回复  |  直到 6 年前
        1
  •  6
  •   user539810 user539810    6 年前

    这个 %v Stringer 接口。但是,要实现这一点,该方法必须存在于值的方法集中。

    T ,其方法集包含任何接收该类型值的方法 T型

    func (t  T) Foo()    //     in the method set of T
    func (t *T) Bar()    // not in the method set of T
    

    *T ,其方法集包含两个接收类型为的值的方法 T型 和类型的指针 *T型 :

    func (t  T) Foo()    //     in the method set of *T
    func (t *T) Bar()    //     in the method set of *T
    

    main ip 带类型 IPAddr ,因此上面的第一组注释代码适用。

    您的第一个示例将起作用,因为 String IP地址 .

    字符串 方法具有类型 *IPAddr ,具有类型 IP地址 .

    总而言之:

                | String() Method | fmt.Print, fmt.Printf, etc.
     Input Type | Receiver        | calls String() implicitly
     ========== | =============== | ===========================
       *IPAddr  |     IPAddr      | Yes
                |    *IPAddr      | Yes
     ---------- + --------------- + ---------------------------
        IPAddr  |     IPAddr      | Yes
                |    *IPAddr      | No
    

    *IP地址 无法接收没有地址的值。例如,尝试执行 IPAddr{}.String() 带着一个 *IP地址 方法接收器。它将无法编译,因为文本值没有地址。如果你用 (&IPAddr{}).String() ,它将工作,因为现在你有一个指针 &IPAddr{} ,如果使用非指针接收器

        2
  •  2
  •   gonutz    6 年前

    问题是你的地图包含类型 IPAddr 它没有 String() *IPAddr 通过a Stringer 接口,因此它使用默认打印。

    var ip IPAddr
    ip.String()
    

    因为在这种情况下,Go足够聪明,它可以调用 函数的地址。Go可以自动获取一个变量的地址来调用它的函数。

    另一方面,你甚至不能打电话 字符串() IP地址 map 具有 [] Here is an example 为了说明这些特性:

    package main
    
    import "fmt"
    
    type IPAddr [4]byte
    
    func (o *IPAddr) String() string {
        return fmt.Sprintf("%v.%v.%v.%v", o[0], o[1], o[2], o[3])
    }
    
    func main() {
        var ip = IPAddr{1, 2, 3, 4}
    
        // printing the value does not call String() because we pass type IPAddr,
        // not type *IPAddr
        fmt.Printf("%v\n", ip)
    
        // but we can call String() on the variable because Go knows how to get its
        // address
        fmt.Println(ip.String())
    
        m := map[int]IPAddr{1: IPAddr{1, 2, 3, 4}}
        fmt.Println(m[1])
        // the following is a compile-time error because Go cannot take the address
        // of things in the map, because the []-operator returns only a copy of the
        // IPAddr
        //fmt.Println(m[1].String())
    }