关于 Go 在 `Return Nil or Pointer to Empty Struct on Error` 上的讨论?

2022-08-12 11:47:48 +08:00
 ryalu
type User struct {}


// 1. return nil
func GetUser() (*User, err) {
	....
    
    return nil, err
}

// 2. return pointer to empty struct
func GetUser() (*User, err) {
	....
    
    return &User{}, err
}

个人会担心下游的不注意( nil 判断)导致进程 panic ,所以基本都是用第二种。想听听大家的意见或见解?

4602 次点击
所在节点    Go 编程语言
82 条回复
bruce0
2022-08-12 19:38:44 +08:00
都返回 error 了,不处理 error, 还去用 这谁也救不了吧, 正常规范应该是, 有 error 都要处理
joesonw
2022-08-12 19:59:18 +08:00
@ryalu 你都 err 了,为什么还要用*User 。Java 里面 catch exception 你还用返回值?
sutra
2022-08-12 20:00:34 +08:00
如果都像 2 那样用,那么 Go 为什么要搞个 nil ?
haoliang
2022-08-12 20:09:11 +08:00
zig 中可以这样 `var x: anyerror!?T`
ailer
2022-08-12 20:10:47 +08:00
@asmoker 这个 error 按你的函数名语义不应该为 nil ,没有获取到那就是有错误
ailer
2022-08-12 20:12:24 +08:00
@ryalu user 都是空的了还不报错吗?没有获取到就是没获取到,不报错给个空的忽悠人啊
egen
2022-08-12 20:20:11 +08:00
@ryalu 这个就更离谱了,err 为空同时返回的 user 为 nil ?如果用户不存在请返回 user not found 的 error ,不要去解决本不存在的问题
zand
2022-08-12 20:45:55 +08:00
@ryalu #39 你应该把这楼写到最前面。。。看到大家都在讨论返回 nil 还是&User{},我也感觉是歪楼了。
理论上来说,按 1 返回,caller 不需要检查返回的 user , 只要 err 为 nil ,就可以放心使用返回的 user 。但实际开发时,被调方写的啥样都有,而且倘若出了 bug ,必然会怪到 caller 身上。反正我是被坑过,所以我检查完 err 后还是会检查下返回值是否为 nil 。
getadoggie
2022-08-12 20:58:59 +08:00
最近正好在书中看到过这个,书中给的原则是:如果方法返回了 error ,那么该方法返回的其它值就不能够再被信任了。
我感觉调用者是否忽略错误是调用者的事,但大家只要遵守上面的原则,应该就没有问题。为了促进大家遵守这个原则,使用方法一更好。
Lighfer
2022-08-12 21:08:16 +08:00
肯定 1 啊。
第 2 种,调用方不管 error 也不管 nil ,那么返回一个空对象,更不能指望 TA 在用这个空对象时,会去判断 User.Id User.Name ,而这种属性在甚至可能会有不少人根据惯性思维认为 Id 或者 Name 是一定存在的
BeautifulSoap
2022-08-12 21:30:36 +08:00
@ryalu 你的想法本身就是有问题的,无论是调用方还是被调用方,都应该遵守一个原则:err != nil 的时候,默认 err 之外的所有一切返回值都是毫无意义的应该直接丢弃(连检查都不应该去检查)。如果你需要添加额外的错误信息,那应该将信息放入 err 而不是从其他返回值上获取。所以你担心的 err 不等于 nil 需要去判断 user 指针,这种事情本身就不应该发生
xth12138
2022-08-12 21:55:36 +08:00
err != nil 的时候,不应该信任 err 以外的返回值
mainjzb
2022-08-12 22:32:47 +08:00
😅看了 39 楼,还是应该用 1 , 用了 2 等于回到 C++了,弱类型各种判断,你烦不烦啊。
ryalu
2022-08-12 22:54:33 +08:00
@zand #48 抱歉,不会操作这个😅
clownpiece
2022-08-12 23:02:27 +08:00
为啥不学 controller-runtime 那套呢

user := &User{}
if err := client.Get(user); err != nil {
...
}
FrankHB
2022-08-13 00:03:38 +08:00
@codehz @neoblackcap 这些说法是有问题的。
是否能够忽略错误,根本上就是应该是接口具有的含义确定。有的接口的用途决定一些错误就一定是实现细节,而应该及时被处理掉;此时 caller 被设计为无权依赖这些实现细节,更不应该被这些泄漏的细节干扰。
只是这里 2 的接口设计怎么都跟允许忽略错误的接口设计需求不搭。

反而一般的接口实现作为程序的一部分,不应该随便决定整个程序是不是能处理错误(况且判断是不是该死其实也是一般意义上的一种“处理”),因为 caller 通常总是比 callee 更配代表整个程序来决定是不是该死掉。所以不能就地处理的错误默认就该甩锅给 caller ,出问题就是 caller 的问题。
如果整个调用链都是默认策略,在这里就是最终 panic ,也就是选 1 。而在某个位置因为接口的设计,可以能出现类似 2 的情况(但不应设计成这样容易误用的接口,下同),只是一般较少见。
这种“默认”的性质是可组合的,叫做 error neutrality 。但是因为语言设计的原因导致一些语言这种“默认”策略编码起来无畏地啰嗦,具体如 C 、Go 、Rust 、Java 用户通常在这方面的意识很弱,或者基本没有。一些 C++用户倒是容易注意这些问题——没事别乱 catch ,要及时 rethrow——于是实现了 exception neutrality ;不过另一部分死脑筋嚷嚷排除 exception 的用户(基本同 C 用户,除了那些会 sjlj 的)这里一样没救。
因为大量初级用户容易默认语言既有设计真实反映了实用需求,这种啰嗦的一个直接问题是让许多用户无法意识到 1 和 2 的比例在实际需求中的差异,以及造成这种差异的理由,而放弃深究问题的来源,停留在流于基于既有经验的瞎蒙,以期望得到 best practice ,却不知道已经踏入了具体语言设计局限性的陷阱之中。
codehz
2022-08-13 00:48:12 +08:00
@FrankHB #56 然后呢,你是要设计一个新语言还是在“现有语言的约束下”寻找比较好的方案呢?
现有 go 的约束,就是没有办法去充分表达错误分支和正常分支的互斥性,而想自动传播异常用 panic+recover 也不是推荐的方案,因此这个情况只能靠开发者自己的规范,那这里的选择,就是用最不容易让其他开发者犯错的方法,使用上述策略,然后在要搞特殊处理的时候再单独写文档说明为什么要这样做。
这帖子是在讨论“已经在用 go”的情况下如何尽可能避免踩坑,而不是来讨论 go 语言设计的哪里不好,也不是来搞语言鄙视链的。(而且 c++异常的喷点也不少,缺少 checked exception ( throws 被移除,noexcept 只能用来标记永远不抛出异常的函数,这个特性好不好另说)或者 effect 机制等类似机制,导致实际上很多时候是开发者忘记处理异常(和标记在文档里),而不是注意到不要 catch ,特别是 call graph 复杂了之后,很难发现某个调用路径下有可能会抛出哪些异常(例如人均忘记的 bad_alloc ,和流处理会遇到的 std::ios_base::failure ),这导致异常本身经常会由于上述疏忽变成实现细节——只有崩了才知道啊原来这个函数会抛出这个异常)
wheeler
2022-08-13 01:20:42 +08:00
返回 copy 好了。
Trim21
2022-08-13 01:31:53 +08:00
var ErrUserNotExist = errors.New("user not exist")

func () {
return nil, ErrUserNotExist
}

然后调用者根据 err!=nil 和 errors.Is(err, ErrUserNotExist)来处理。
Trim21
2022-08-13 01:49:15 +08:00
4 把返回类型写成结构体,不过有没有 err 都得返回个结构体,下游永远不可能 panic

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

https://www.v2ex.com/t/872400

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

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

© 2021 V2EX