Golang中关于Type Writer的问题探讨

Golang中关于Type Writer的问题探讨

type Writer interface {
    Write(p []byte) (n int, err error)
}

这里的p是一个变量的示例吗?还是必须总是使用p? 关于n也有同样的问题。

“Writer是包装了基本Write方法的接口。”

包装是什么意思?

“Write将len§个字节从p写入底层数据流。它返回从p写入的字节数(0 <= n <= len§)以及导致写入提前停止的任何错误。如果返回的n < len§,Write必须返回一个非nil错误。Write不能修改切片数据,即使是临时修改。”

p (0 <= n <= len§) 我对这个有模糊的理解,但没有完全掌握。

n < len§也是同样的情况。

底层是什么意思?

“实现不能保留p。”

这是什么意思?


更多关于Golang中关于Type Writer的问题探讨的实战教程也可以访问 https://www.itying.com/category-94-b0.html

6 回复

谢谢!非常有帮助。我今天会再仔细研究一下

更多关于Golang中关于Type Writer的问题探讨的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我查看了您的回复,非常有帮助

type Writer interface { Write(p [][byte] (n int, err ) }

type FooWritter struct {}

func (f *FooWritter) Write(p [][byte] (n int, err ) {  return 0, nil }

type BarWritter struct { FooWritter }

func SomeFunction(w Writter) { w.Write([]byte{1,2,3}) }


foo := new(FooWritter )
bar := new(BarWritter)

SomeFunction(foo)
SomeFunction(bar)

Write 函数的文档语境中,“底层流"是指您将 p 字节切片写入的数据源。例如,*io.File 通过其自身的 Write 成员函数实现了 io.Writer。该成员函数接收 p 字节切片中的数据,并将这些数据写入其"底层流”:即磁盘上的文件。

什么是数据源?

从基本概念来看,似乎是指数据的来源。那么这是指回溯到软件包吗?还是计算机中某种神秘的固有存在?

根据维基百科的定义… DataSource 是指从服务器建立到数据库的连接名称 对我来说,连接是某种电子层面的概念。

我知道 []byte 表示字节切片,但 [][]byte 是什么?

我的资料显示函数的语法是:func (接收者) 标识符(参数) (返回值) { 代码 }

那么在:

func (w *PRetainerWriter) Write(p []byte) (n int, err error) {
    // 保存 p 供后续使用
    w.ps = append(w.ps, p)

    // 既然我们违反了 Write 的约定,也让我们返回无效的返回值吧!
    // n 本应大于等于 0 或小于等于 len(p)
    // 所以让我们返回 -1!
    return -1, nil
}

其中 (w *PRetainerWriter) 是接收者吗? Write 是标识符吗? (p []byte) 是参数吗? 其余部分就是代码?

我正在尝试理解什么是接收者。使用这段代码:Go Playground - The Go Programming Language,我的老师评论说"bar 接收一个字符串"。那么在这段代码中,(s string) 是接收者吗?这是否意味着 bar 接收任何通过 bar 传递的字符串?

关于函数的更多问题。希望您不介意我改变了主题。不知何故这些问题是相关的。

在:* Go Playground - The Go Programming Language string 是返回值吗? 为什么它在那里,而不在这里:func bar(s string) {

cherilexvold1974:

p 在这里是一个变量的示例吗?还是必须始终使用 p? 关于 n 也有同样的问题。

我有两个回答:

  1. 从技术上讲,它们只是变量名,你可以随意命名。
  2. 然而,对于像 io 包中那些非常常见的类型,按照惯例保持返回值名称为 pnerr 通常是个好主意。

cherilexvold1974:

“Writer 是封装了基本 Write 方法的接口。”

"封装"是什么意思?

我认为这里的"封装"一词没有技术含义。你可以说接口"捆绑"、"包含"或"封装"它们的成员函数。Writer 类型包含一个成员函数:Write,因此它"封装"了这个函数。

cherilexvold1974:

(0 <= n <= len(p))

我对这个有一点模糊的理解,但还没有完全掌握。

(0 <= n <= len(p)) 意味着当 Write 被调用返回后,它的 n 返回值将大于等于 0 且小于等于 p 字节切片的长度。

cherilexvold1974:

"底层"是什么意思?

Write 函数文档的上下文中,“底层流"是你将 p 字节切片写入的数据源。例如,*io.File 通过其自己的 Write 成员函数实现了 io.Writer。该成员函数接收 p 字节切片中的数据,并将这些数据写入其"底层流”:磁盘上的文件。

cherilexvold1974:

“实现不得保留 p。”

这是什么意思?

这意味着 Write 函数不应存储 p 值。例如,这里有一个违反该文档要求的糟糕的 io.Writer 实现:

type PRetainerWriter struct {
    ps [][]byte
}

func (w *PRetainerWriter) Write(p []byte) (n int, err error) {
    // 将 p 保留供后续使用
    w.ps = append(w.ps, p)

    // 既然我们违反了 Write 的约定,也返回无效的返回值吧!
    // n 应该大于等于 0 或小于等于 len(p)
    // 所以我们返回 -1!
    return -1, nil
}

在Go语言中,Writer接口的Write方法参数和返回值有明确的语义规范,我来逐一解释你的问题:

关于参数名p和返回值n

参数名p和返回值n只是约定俗成的命名,不是强制要求。你可以使用任何合法的参数名,但保持一致性有助于代码可读性。

// 这些写法都是合法的,但推荐使用标准命名
type MyWriter interface {
    Write(data []byte) (written int, err error)
}

type AnotherWriter interface {
    Write(buffer []byte) (count int, err error)
}

"包装"的含义

"包装"在这里指的是接口对底层实现进行了抽象封装。Writer接口定义了一个契约,任何实现了Write方法的类型都可以被当作Writer使用,无论其底层是如何实现的。

type FileWriter struct {
    file *os.File
}

func (fw *FileWriter) Write(data []byte) (int, error) {
    return fw.file.Write(data) // 包装了文件系统的Write操作
}

type BufferWriter struct {
    buffer *bytes.Buffer
}

func (bw *BufferWriter) Write(data []byte) (int, error) {
    return bw.buffer.Write(data) // 包装了内存缓冲区的Write操作
}

关于n和len§的关系

n表示实际成功写入的字节数,它总是满足 0 <= n <= len(p)

func ExampleWriteBehavior() {
    var w Writer // 假设是某个实现了Writer的类型
    
    data := []byte("hello world")
    n, err := w.Write(data)
    
    // n的可能情况:
    // - n == len(data): 全部写入成功
    // - n < len(data): 部分写入,必须返回错误
    // - n == 0: 没有写入,必须返回错误
    
    if err != nil {
        fmt.Printf("写入了 %d/%d 字节,错误: %v\n", n, len(data), err)
    }
}

"底层"的含义

"底层"指的是Writer接口具体实现所操作的实际数据存储或传输目标:

// 底层是文件系统
file, _ := os.Create("output.txt")
fileWriter := os.FileWriter{file}

// 底层是网络连接
conn, _ := net.Dial("tcp", "example.com:80")
connWriter := net.ConnWriter{conn}

// 底层是内存缓冲区
buf := &bytes.Buffer{}
bufWriter := bytes.BufferWriter{buf}

"不能保留p"的含义

这意味着Write方法实现不能在方法调用结束后继续持有对传入切片的引用:

// 错误的实现 - 保留了p的引用
type BadWriter struct {
    storedData []byte
}

func (bw *BadWriter) Write(p []byte) (int, error) {
    bw.storedData = p // 错误:保留了p的引用
    return len(p), nil
}

// 正确的实现 - 不保留p的引用
type GoodWriter struct {
    buffer *bytes.Buffer
}

func (gw *GoodWriter) Write(p []byte) (int, error) {
    // 创建数据的副本,不保留原始切片的引用
    data := make([]byte, len(p))
    copy(data, p)
    gw.buffer.Write(data)
    return len(p), nil
}

这个限制确保了调用方可以在Write返回后安全地重用或修改原始切片,而不会影响Writer的内部状态。

回到顶部