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
谢谢!非常有帮助。我今天会再仔细研究一下
更多关于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 也有同样的问题。
我有两个回答:
- 从技术上讲,它们只是变量名,你可以随意命名。
- 然而,对于像
io包中那些非常常见的类型,按照惯例保持返回值名称为p、n和err通常是个好主意。
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的内部状态。

