liuxu
2022-08-12 13:53:34 +08:00
不止 golang ,外面这几天吵的不可开交的语言都有 nil/null 这个问题
要回答这个问题,可以从 rust 的思想入手
首先在 php/java 这类常规语言开发中,要么返回 null ,要么返回空对象 User{},返回 null 就有个有名的 java 常见的运行时异常 NullPointException ,php 就是 call xxx on null
作为强类型语言,java 定义方法是需要有确定返回类型,如果返回 User 却返回 null ,但是 null 明显不是 User 类型,这个很矛盾,所以调用者即使知道方法返回 User ,却还要处理 null 的情况,而 php 可以不定义返回类型,所以锅就强行推给了方法的调用者
现在就有了楼主说的 2 种解决办法:
1. 返回 null ,让调用者处理 null 问题(目前常规解决方案)
2. 返回空 User ,调用者放心使用返回值,而不用担心问题,但是在业务中却需要注意空 User 问题,例如在 php/laravel 中调用 guard 的方法,$user->isAdmin()就会产生歧义,到底是没有这个 user ,还是 user 的权限不是管理员,只是普通用户
为了解决这个问题,rust 给出了以下解决方案:
首先 rust 中有 Option 这个东西,枚举为:
enum Option<T> {
None,
Some(T),
}
对于你的问题,返回就应该是 Some(User)或者 None ,在方法定义中,由于返回是 enum 枚举 Option<User>,所以 None 和 Some(User)在类型检查中都是合格的
但是到了方法调用时,调用者必须处理 Option<T>,因为 Some(User) != User ,None != User ,即使是 Some(User),也得手动将 Some(User)解析为 User 才能使用
编译器会检查这个问题,所以就不会有运行时异常了,也不会有返回 User 却返回 null 还合规这种矛盾的事情了
golang 的解决方案稍微变换了一下,按照常规解决方案是返回(nil, err),这样在调用时:
if user, err := x.GetUser(); err != nil {return err}
golang 在调用后 if 中处理,如果 err 不为 nil 则 user 值不合规,而不必管是 nil 还是空 User{}
说起来这个和 rust 的 Option 有一点异曲同工之妙
区别就是 rust 是为了编译时合规而给出了 Option 方案,golang 是运行时使用判断 err 给出了 if 方案
而关于担心下游不注意 nil 判断就很多余了,随便给了 api 文档说明:
func (b *Builder) Write(p []byte) (int, error)
方法定义既然给出了(int, error),如果有 error!=nil ,不管 int 真的是 int 还是 nil ,此时都不合规,调用者不能使用,这就是 golang 的规范
当然在 php/java 常用另一种做法,就是在 GetUser()中没有找到方法就 throw 个 Exception 而不是返回 null ,让外面 try/catch 解决,没有触发异常则返回的 User 是合规的对象
对于复杂的代码来说,经常有 try 包 try 的代码,看上去反而有些奇怪,于是有了 php/java 的 try 加 if 判断的混合用法,反倒有点混乱的感觉,具体喜好还是看个人