golang interface 和 struct 添加方法的区别

在 Go 语言中,struct 和 interface 都可以关联方法,但它们的方式不同:

  1. struct 添加方法:

结构体(struct)本身不直接包含方法,但可以通过定义一个指向该结构体类型的指针作为接收者的函数来为结构体"添加"方法。

复制代码
type MyStruct struct {
    // fields
}

func (s *MyStruct) MyMethod() {
    // method body
}

这里的 MyMethod 是一个与 MyStruct 关联的方法,通过指针接收者 *MyStruct 实现。

  1. interface 添加方法:

接口(interface)并不直接定义方法,而是定义了一组方法签名。当一个结构体实现了接口所要求的所有方法时,我们说这个结构体实现了该接口。

复制代码
type MyInterface interface {
    MyMethod()
}

// 不需要显式声明实现,只要MyStruct有匹配的方法签名即可
func (s *MyStruct) MyMethod() {
    // method body
}

在上面的例子中,MyStruct 通过其 MyMethod 实现了 MyInterface,无需任何额外的代码。

总结来说,结构体通过定义"方法接收者"来关联方法 ,而接口通过定义"一组方法签名"来间接要求实现它的类型具备相应的方法

实例见: $GOROOT/src/net/net.go 局部

Conn 接口表示一个通用的面向流的网络连接,并定义了读取、写入、关闭以及为 I/O 操作设置截止时间的多种方法。

可以在多个goroutine中同时调用其方法。

Read 方法从连接中读取数据到给定的字节片,并返回读取的字节数和遇到的任何错误。

Write 方法将给定字节片中的数据写入连接,并返回写入的字节数和遇到的任何错误。

Close 方法关闭连接并返回关闭过程中发生的任何错误。

LocalAddr 方法返回连接的本地网络地址(如果已知)。

RemoteAddr 方法返回连接的远程网络地址(如果已知)。

SetDeadline 方法为连接设置读取和写入的截止时间。如果超过截止时间,后续的 I/O 操作会失败并返回错误。

SetReadDeadline 方法为未来的 Read 调用及当前阻塞的 Read 调用设置截止时间。

SetWriteDeadline 方法为未来的 Write 调用及当前阻塞的 Write 调用设置截止时间。即使写入超时,也可能返回 n > 0,表明部分数据已成功写入。

conn 结构体Conn 接口的一个具体实现,它使用 netFD 对象来表示底层的文件描述符。

复制代码
// Conn is a generic stream-oriented network connection.
//
// Multiple goroutines may invoke methods on a Conn simultaneously.
type Conn interface {
    Read(b []byte) (n int, err error)
    Write(b []byte) (n int, err error)
    Close() error
    LocalAddr() Addr
    RemoteAddr() Addr
    SetDeadline(t time.Time) error
    SetReadDeadline(t time.Time) error
    SetWriteDeadline(t time.Time) error
}

type conn struct {
    fd *netFD
}

func (c *conn) ok() bool { return c != nil && c.fd != nil }

// Implementation of the Conn interface.

func (c *conn) Read(b []byte) (int, error) {
    if !c.ok() {
        return 0, syscall.EINVAL
    }
    n, err := c.fd.Read(b)
    if err != nil && err != io.EOF {
        err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
    }
    return n, err
}

func (c *conn) Write(b []byte) (int, error) {
    if !c.ok() {
        return 0, syscall.EINVAL
    }
    n, err := c.fd.Write(b)
    if err != nil {
        err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
    }
    return n, err
}

func (c *conn) Close() error {
    if !c.ok() {
        return syscall.EINVAL
    }
    err := c.fd.Close()
    if err != nil {
        err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
    }
    return err
}

func (c *conn) LocalAddr() Addr {
    if !c.ok() {
        return nil
    }
    return c.fd.laddr
}

func (c *conn) RemoteAddr() Addr {
    if !c.ok() {
        return nil
    }
    return c.fd.raddr
}

func (c *conn) SetDeadline(t time.Time) error {
    if !c.ok() {
        return syscall.EINVAL
    }
    if err := c.fd.SetDeadline(t); err != nil {
        return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
    }
    return nil
}

func (c *conn) SetReadDeadline(t time.Time) error {
    if !c.ok() {
        return syscall.EINVAL
    }
    if err := c.fd.SetReadDeadline(t); err != nil {
        return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
    }
    return nil
}

func (c *conn) SetWriteDeadline(t time.Time) error {
    if !c.ok() {
        return syscall.EINVAL
    }
    if err := c.fd.SetWriteDeadline(t); err != nil {
        return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
    }
    return nil
}

func (c *conn) SetReadBuffer(bytes int) error {
    if !c.ok() {
        return syscall.EINVAL
    }
    if err := setReadBuffer(c.fd, bytes); err != nil {
        return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
    }
    return nil
}

func (c *conn) SetWriteBuffer(bytes int) error {
    if !c.ok() {
        return syscall.EINVAL
    }
    if err := setWriteBuffer(c.fd, bytes); err != nil {
        return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
    }
    return nil
}

func (c *conn) File() (f *os.File, err error) {
    f, err = c.fd.dup()
    if err != nil {
        err = &OpError{Op: "file", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
    }
    return
}

Link:https://www.cnblogs.com/farwish/p/18236119

相关推荐
@东辰7 小时前
【golang-技巧】-自定义k8s-operator-by kubebuilder
开发语言·golang·kubernetes
@东辰8 小时前
【golang-技巧】- 定时任务 - cron
开发语言·golang·cron
jerry60914 小时前
7天用Go从零实现分布式缓存GeeCache(改进)(未完待续)
分布式·缓存·golang
杜杜的man15 小时前
【go从零单排】Closing Channels通道关闭、Range over Channels
开发语言·后端·golang
甘橘籽20 小时前
【RPC】 gRPC、pb基本使用--经验与总结
golang
杜杜的man20 小时前
【go从零单排】HTTP客户端和服务端
开发语言·http·golang
材料苦逼不会梦到计算机白富美21 小时前
golang分布式缓存项目 Day6 防止缓存击穿
分布式·缓存·golang
杜杜的man1 天前
【go从零单排】Environment Variables环境变量
golang
材料苦逼不会梦到计算机白富美1 天前
golang HTTP基础
http·golang·iphone
友大冰1 天前
Go 语言已立足主流,编程语言排行榜24 年 11 月
开发语言·后端·golang