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

相关推荐
卑微的小鬼4 小时前
rpc和http的区别,为啥golang使用grpc 不使用http?
http·rpc·golang
大脑经常闹风暴@小猿7 小时前
1.1 go环境搭建及基本使用
开发语言·后端·golang
tekin9 小时前
Go、Java、Python、C/C++、PHP、Rust 语言全方位对比分析
java·c++·golang·编程语言对比·python 语言·php 语言·编程适用场景
zhoupenghui16818 小时前
golang时间相关函数总结
服务器·前端·golang·time
孤雪心殇18 小时前
简单易懂,解析Go语言中的Map
开发语言·数据结构·后端·golang·go
闲猫20 小时前
go 反射 interface{} 判断类型 获取值 设置值 指针才可以设置值
开发语言·后端·golang·反射
Ciderw1 天前
LLVM编译器简介
c++·golang·编译·编译器·gcc·llvm·基础设施
朗迹 - 张伟1 天前
Golang连接使用SqlCipher
开发语言·后端·golang
闲猫1 天前
go 网络编程 websocket gorilla/websocket
开发语言·websocket·golang
Ciderw1 天前
MySQL日志undo log、redo log和binlog详解
数据库·c++·redis·后端·mysql·面试·golang