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

相关推荐
__AtYou__2 小时前
Golang | Leetcode Golang题解之第448题找到所有数组中消失的数字
leetcode·golang·题解
千年死缓3 小时前
go+redis基于tcp实现聊天室
redis·tcp/ip·golang
吃着火锅x唱着歌7 小时前
Redis设计与实现 学习笔记 第五章 跳跃表
golang
技术卷10 小时前
Redis数据库与GO完结篇:redis操作总结与GO使用redis
数据库·redis·golang
white.tie12 小时前
vscode配置golang
ide·vscode·golang
陈序缘12 小时前
Go语言实现长连接并发框架 - 任务管理器
linux·服务器·开发语言·后端·golang
0x派大星17 小时前
【Golang】语法基础——切片:灵活、高效的数据处理利器
golang
技术卷1 天前
GO网络编程(二):客户端与服务端通信【重要】
golang·网络编程
小帅吖1 天前
浅析Golang的Context
开发语言·后端·golang
MarisTang1 天前
Go语言实现随机森林 (Random Forest)算法
算法·随机森林·golang