因为errorString的Error()方法定义在errorString指针接收器上,只有errorString才实现error接口;若改用值接收器,则errorString{"x"}本身即可满足接口。

error 接口本身没有底层原理——它就是一个普通接口,唯一要求是实现 Error() 方法。 真正影响行为的是方法接收器类型、接口实现规则和标准库的隐式调用逻辑。
为什么 errors.New("x") 必须返回指针?
因为标准库中 errorString 的 Error() 方法是定义在 *errorString 上的(指针接收器):
-
errorString{"x"}是值类型,不包含Error()方法,无法满足error接口 -
&errorString{"x"}是指针类型,其方法集包含Error(),自然实现error - 如果改用值接收器
func (e errorString) Error() string,那errorString{"x"}就能直接赋值给error变量
fmt.Println 为什么会自动调用 Error()?
这不是 error 接口的特性,而是 fmt 包的显式逻辑:
-
fmt在格式化任意值前,会检查是否实现了error接口 - 若满足,就自动调用
.Error()并打印返回的string - 这跟
Stringer接口的处理方式一致,属于 fmt 的“友好约定”,不是语言强制行为 - 你自己写函数不会自动触发——必须显式调用
err.Error()或交给fmt系列函数
函数类型也能实现 error 接口?
可以,但容易混淆本质:
- 先定义函数别名:
type binFunc func(int, int) int - 再为该类型绑定方法:
func (f binFunc) Error() string { return "oops" } - 此时
binFunc(add)既是可调用函数,又是error值(因类型binFunc拥有Error()) - 注意:这不是“函数返回错误”,而是“函数值本身被当作了错误对象”——语义上非常规,慎用于生产代码
最常被忽略的一点:接口实现只看方法集,不看值还是指针;但方法集是否包含某个方法,完全取决于接收器类型。写自定义错误时,别只盯着 Error() 方法签名,先想清楚——你打算用值还是指针来承载它。











