美文网首页Go语言用例Go知识库
golang的struct里面嵌入interface

golang的struct里面嵌入interface

作者: CodingCode | 来源:发表于2018-04-26 16:40 被阅读13次

    golang的struct里面嵌入interface

    先通过几个例子来说明这样用法。

    例子1

    定义一个Interface II包含两个函数声明

    1. F1()
    2. F2()

    然后定义一个struct SS,它实现了函数F1和F2,这样SS其实就是II的一个实现。

    package main
    
    import (
        "fmt"
    )
    
    type II interface {
        F1()
        F2()
    }
    
    type SS struct {
        vv int
    }
    
    func (ss *SS) F1() {
    }
    
    func (ss *SS) F2() {
    }
    
    func main() {
        var ss SS = SS{}
        var ii II = &ss
    
        fmt.Printf("ss:value=[%v]\n", ss)
        fmt.Printf("ii:value=[%v]\n", ii)
    } 
    

    编译运行,输出如下

    $ go build && ./main
    ss:value=[{0}]
    ii:value=[&{0}]
    

    例子2

    如果在struct SS中不实现F1和F2,或者只实现F1或者F2,还能不能继续使用呢。
    还是前面的代码,我们注释掉F2的定义。

    package main
    
    import (
        "fmt"
    )
    
    type II interface {
        F1()
        F2()
    }
    
    type SS struct {
        vv int
    }
    
    func (ss *SS) F1() {
    }
    
    //func (ss *SS) F2() {
    //}
    
    func main() {
        var ss SS = SS{}
        var ii II = &ss
    
        fmt.Printf("ss:value=[%v]\n", ss)
        fmt.Printf("ii:value=[%v]\n", ii)
    }
    

    编译运行

    $ go build && ./main
    # testinterfacestruct
    ./main.go:25: cannot use &ss (type *SS) as type II in assignment:
            *SS does not implement II (missing F2 method)
    

    编译器报错,不能把ss赋值给ii,因为SS不是II的实现。

    例子3

    那么如何解决上述问题呢,嵌入interface的作用就出来了。我们把interface作为struct的一个匿名成员,就可以假设struct就是此成员interface的一个实现,而不管struct是否已经实现interface所定义的函数。

    package main
    
    import (
        "fmt"
    )
    
    type II interface {
        F1()
        F2()
    }
    
    type SS struct {
        vv int
        II
    }
    
    //func (ss *SS) F1() {
    //}
    
    //func (ss *SS) F2() {
    //}
    
    func main() {
        var ss SS = SS{}
        var ii II = &ss
    
        fmt.Printf("ss:value=[%v]\n", ss)
        fmt.Printf("ii:value=[%v]\n", ii)
    }
    

    这个例子中,struct SS没有实现interface II的任何一个函数,只是在声明struct的时候把II作为一个匿名成员,此时 var ii II = &ss 赋值语句没有任何错误,可见ss已经被认为是interface II的实现。

    所以嵌入interface可以使得一个struct具有interface的接口,而不需要实现interface中的有声明的函数。

    例子4

    既然没有实现函数,那么如何调用接口的呢?答案是,没有实现肯定是不能调用啊,直接crash了;只能调用已经实现的函数。
    还是在上述例子中,我们定义F1,没有实现F2,那么可以正常调用F1,但是不能调用F2

    package main
    
    import (
        "fmt"
    )
    
    type II interface {
        F1()
        F2()
    }
    
    type SS struct {
        vv int
        II
    }
    
    func (ss *SS) F1() {
        fmt.Printf("in SS::F1()\n")
    }
    
    //func (ss *SS) F2() {
    //}
    
    func main() {
        var ss SS = SS{}
        var ii II = &ss
    
        fmt.Printf("ss:value=[%v]\n", ss)
        fmt.Printf("ii:value=[%v]\n", ii)
    
        ii.F1()
    }
    

    运行结果

    ss:value=[{0 <nil>}]
    ii:value=[&{0 <nil>}]
    in SS::F1()
    

    如果我们运行F2呢,会出什么结果?

    把main函数改成试试:

    func main() {
        var ss SS = SS{}
        var ii II = &ss
    
        fmt.Printf("ss:value=[%v]\n", ss)
        fmt.Printf("ii:value=[%v]\n", ii)
    
        // ii.F1()
        ii.F2()
    }
    

    编译运行:

    $ go build && ./main
    ss:value=[{0 <nil>}]
    ii:value=[&{0 <nil>}]
    panic: runtime error: invalid memory address or nil pointer dereference
    [signal SIGSEGV: segmentation violation code=0x1 addr=0x28 pc=0x47d680]
    
    goroutine 1 [running]:
    main.(*SS).F2(0xc42000a300)
            <autogenerated>:3 +0x40
    main.main()
            /home/.../go/src/main/main.go:33 +0x185
    

    可见编译器成功完成了编译,但是在运行的时候出错了,因为F2函数根本找不到。

    例子5

    我们分析一个嵌入Interface的实现;在前面我们已经看到struct和interface的内容了。

    ss:value=[{0 <nil>}]
    ii:value=[&{0 <nil>}]
    

    ss的内容包含一个0值和一个nil值,0值vv的值,那么<nil>推测就是II的值了;增强一下代码:

    package main
    
    import (
        "fmt"
        "unsafe"
    )
    
    type II interface {
        F1()
        F2()
    }
    
    type SS struct {
        vv int
        II
        ww int
    }
    
    func (ss *SS) F1() {
        fmt.Printf("in SS::F1()\n")
    }
    
    func (ss *SS) F2() {
        fmt.Printf("in SS::F2()\n")
    }
    
    func main() {
        var ss SS = SS{vv:1,ww:2}
        var ii II = &ss
    
        fmt.Printf("ss:size=[%d],value=[%v]\n", unsafe.Sizeof(ss), ss)
        fmt.Printf("ii:size=[%d],value=[%v]\n", unsafe.Sizeof(ii), ii)
    }
    

    运行结果:

    $ go build && ./main
    ss:size=[32],value=[{1 <nil> 2}]
    ii:size=[16],value=[&{1 <nil> 2}]
    

    可见ss占用32字节,前8字节和后8字节分别是变量vv和ww,中间的16字节必须是给II的;这是一个占位符,没有具体的值,其值为nil。

    这个地方有疑问,为什么是一个nil的占位符。

    相关文章

      网友评论

        本文标题:golang的struct里面嵌入interface

        本文链接:https://www.haomeiwen.com/subject/hhnplftx.html