go 返回错误的时候, 返回的值应该可用吗

2025 年 11 月 6 日
 shinonome

现在写的一个函数, 会返回多种错误, 我想的是在一些错误的时候, 值也是部份可用的, 在另一些错误的时候, 值是不可用的

之前看到有说函数返回错误的时候, 应该默认正常返回的值为 nil, 不知道有没有这个说法

3541 次点击
所在节点    Go 编程语言
32 条回复
deplives
2025 年 11 月 6 日
返回的值可用那叫错误吗?
YanSeven
2025 年 11 月 6 日
这会造成混乱吧。

另外,为什么会出现错误的时候,“值是部分可用”?是函数返回多个值,然后某几个可用吗。
那这种情况是不是一个函数揉了太多的东西了,有必要放在一个函数里面返回一堆值吗,把功能拆出来,拆成几个小函数不可以吗。
kneo
2025 年 11 月 6 日
可以,但是你需要文档写清楚,并且考虑返回值类型而不是指针。
aladdinding
2025 年 11 月 6 日
没有硬性规定
unused
2025 年 11 月 6 日
只是一种约定,反例: https://pkg.go.dev/io#Reader
shinonome
2025 年 11 月 6 日
@deplives #1 部份可用嘛, 一个结构体从一个网页去解析数据(网站数据更新不及时), 拿到了部份可用数据, 可以勉强进行下一步了, 但是也要分辨下进行处理
46fo
2025 年 11 月 6 日
// Write writes len(b) bytes from b to the File.
// It returns the number of bytes written and an error, if any.
// Write returns a non-nil error when n != len(b).
func (f *File) Write(b []byte) (n int, err error) {
shinonome
2025 年 11 月 6 日
@kneo #3 感谢回答
shinonome
2025 年 11 月 6 日
@YanSeven #2 是一个流程的一个部份, 那个部份的解析能有一些数据, 但会因为时间太早了, 解析不对, 但也有一些可用的数据, 所以想着也返回个错误好让上面知道不是网页不对或网络引起的
guanzhangzhang
2025 年 11 月 6 日
你可以实现两个接口,一个是 Error 接口,另一个是你定义的接口
PTLin
2025 年 11 月 6 日
你需要的是把数据包装到错误中。
```go
type MyErr struct {
value int
}

func (err *MyErr) Error() string {
return "MyErr"
}

func test(a int) (int, error) {
if a%2 == 0 {
return a, nil
}
return 0, &MyErr{value: a}

}
func main() {
_, err := test(1)
if err != nil && err.Error() =="MyErr"{
fmt.Printf("error %d\n",err.(*MyErr).value);
}
}
```
shinonome
2025 年 11 月 6 日
@PTLin #11 对哦, 是这样的
gongym
2025 年 11 月 6 日
看起来是很正常的需求,没必要自定义 error

在一个有很多步骤的逻辑中,虽然中间某一步骤报错,但是仍然根据返回的可用值继续进行,这个操作没啥毛病

go 语言挺自由的,没有那么多严格规范
simon8410
2025 年 11 月 6 日
从程序流程角度看,发生错误之后,程序会进入错误处理流程,即使部分结果可用意义也不大了,除非你在错误处理流程中做正常的业务逻辑处理,一般不会这么做,也不推荐。
kuanat
2025 年 11 月 6 日
参考官方的设计意图:

https://go.dev/blog/errors-are-values
https://go.dev/blog/go1.13-errors

我补充一点个人理解:

Golang 语境中的错误 error 是一种可以预期的行为,预期之外的叫 Panic (对应其他编程语言中的 Exception )。

基于这种思想,Golang 中的错误处理有两个特点:

第一个特点就是上面两篇官方文档提到的,错误是值,使用这个值的方式是 wrap/unwrap ;

第二个特点是 Golang 主张显式控制流,所有的错误都应该按照调用链传播,并在恰当的位置进行处理。

这里“处理”的含义是停止传播,即忽略也是一种处理方式。
gongym
2025 年 11 月 6 日
另外就算是报错,也不能简单的定义为流程无法进行

比如有些程序某些接口很容易因为各种原因无法获取到最新的值,选择重试几次,或者忽略此时的错误就可以了。是不会影响其他接口的获取和整体的刷新逻辑的
PTLin
2025 年 11 月 6 日
@shinonome 而且这种错误里包值的做法是非常场景的,为此 go 还内置了 errors 包替代这种手动转型和判断。
InDom
2025 年 11 月 6 日
您输入的密码部分有误(第 1 、3 、4 、6 位错误).

错误了, 就不应该在给出部分正确的信息, 除非这个错误本身就是可接受的, 比如同时向 100 个 API 推送消息, 但有个别 API 失败了这种场景(不影响主流程的).

大家有共识, 也不算问题.
looplj
2025 年 11 月 6 日
那就别返回错误,因为看起来你的这个场景不是错误,部分失败是一个正常的业务流程。

返回一个 Result 之类的结构,里面定义状态, 成功,失败,部分失败之类的。
eudore
2025 年 11 月 6 日
标准库有示例, 返回值和 error 同时不为空。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://study.congcong.us/t/1170954

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX