V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
void1900
V2EX  ›  Go 编程语言

golang,获取一条记录,数据库找不到记录,是返回特殊的 error 还是返回 nil , error 也返回 nill

  •  
  •   void1900 · 2016-07-29 12:56:43 +08:00 · 1932 次点击
    这是一个创建于 3074 天前的主题,其中的信息可能已经有所发展或是发生改变。

    golang ,获取一条记录,数据库找不到记录,是返回 error 还是 返回对象 nil , error 也返回 nill

    比如用用户 ID 获取用户资料

    我是返回一个特殊的 error

    func (* UserModel) GetUser(uid uint) user User, err error {
       ....
       return user, ErrorNotFound
    }
    

    还是返回 nil, nil

    func (* UserModel) GetUser(uid uint) user *User, err error {
       ....
       return nil, nil
    }
    
    26 条回复    2016-08-01 17:04:16 +08:00
    ryanking8215
        1
    ryanking8215  
       2016-07-29 13:03:19 +08:00
    我选 nil, nil
    armandinho
        2
    armandinho  
       2016-07-29 13:11:44 +08:00
    通常是这么来的。

    func (* UserModel) GetUser(uid uint) user *User, err error {
    ....
    return nil, nil
    }

    func (* UserModel) MustGetUser(uid uint) user User, err error {
    ....
    return user, ErrorNotFound
    }
    void1900
        3
    void1900  
    OP
       2016-07-29 13:23:22 +08:00
    @ryanking8215 我也喜欢 nil,nil 这种 不过我刚开始用 golang ,所以比较不确定。。
    void1900
        4
    void1900  
    OP
       2016-07-29 13:23:53 +08:00
    @armandinho 好像也可以,不过一般不会定义两个功能几乎一样的方法吧。。
    leitwolf
        5
    leitwolf  
       2016-07-29 13:26:23 +08:00
    user=nil,err=errors.New("user not found")
    return;
    windy0925
        6
    windy0925  
       2016-07-29 13:31:26 +08:00
    error 应该返回 nil
    cloudzhou
        7
    cloudzhou  
       2016-07-29 13:32:44 +08:00
    这个问题在于 GetUser 没有找到用户,到底算不算一种 error ,就看你的定义了
    如果算 error ,一个比较麻烦的地方是,按照 go 的哲学,所有 error 都要明显的 check
    在检测错误的时候,你还需要排除 ErrorNotFound 这种情况,就比较繁琐
    zhujinliang
        8
    zhujinliang  
       2016-07-29 13:39:39 +08:00 via iPhone
    @armandinho
    Must 开头的函数应该不返回错误,有错误就 panic
    yanyuan2046
        9
    yanyuan2046  
       2016-07-29 13:39:45 +08:00
    我使用第二种,在实际项目中每个错误码都是特定的,查询错误是 ErrGetData ,数据不存在是 ErrDataNotExist ,以此类推。这个错误码不是字符串,而是一个对象
    type errorCode {
    ID string
    Namespace string
    Code int32
    Message string
    }
    huijiewei
        10
    huijiewei  
       2016-07-29 13:41:13 +08:00
    返回 nil ,不管啥语言,不要在内部乱抛出异常
    qwepoidjdj
        11
    qwepoidjdj  
       2016-07-29 15:18:44 +08:00
    这里看你对错误的定位
    我是这样想的(做的) 看这个方法具体面对的层级
    如果只是在数据库访问层级 返回 nil 肯定是比 err 合理 因为对于数据库本身来说 就是没有查到数据而不是产生了错误
    但是对于业务处理层来说 可能拿到了 nil 以后需要返回一个 err 来通告操作的人
    gamexg
        12
    gamexg  
       2016-07-29 15:22:45 +08:00
    nil,nil

    实现简单,不用费事的区分开数据库错误还是不存在。
    否则还需要定义不同的 error 来区分是数据库错误还是不存在。
    evilgod528
        13
    evilgod528  
       2016-07-29 18:45:05 +08:00
    mgo 是返回 ErrNotFound
    evilgod528
        14
    evilgod528  
       2016-07-29 18:47:47 +08:00
    如果返回 nil,nil 那么,每次得到的 user 还得检查是否 nil ,而如果你查到到的 error 为 nil 的话,那么 user 可能有值
    evilgod528
        15
    evilgod528  
       2016-07-29 18:48:33 +08:00
    @evilgod528 user 肯定有值,打快了,敲错字了
    magicdawn
        16
    magicdawn  
       2016-07-29 19:14:53 +08:00
    @armandinho

    Must 一般是 panic 吧
    janxin
        17
    janxin  
       2016-07-29 19:30:42 +08:00
    return user, ErrorNotFound
    janxin
        18
    janxin  
       2016-07-29 19:34:53 +08:00
    另外其实 golang 中的 error 是个 interface ,所以利用 @yanyuan2046 提到的错误扩展方式其实非常方便
    orvice
        19
    orvice  
       2016-07-29 20:28:34 +08:00
    nil nil
    zhx1991
        20
    zhx1991  
       2016-07-29 20:50:08 +08:00
    看业务.
    raincious
        21
    raincious  
       2016-07-29 20:57:14 +08:00
    我觉得这种问题没什么好纠结的。

    返回 error 是考虑到后面的过程能截获这个错误然后进行处理,而标记成 Must 的函数则是这个函数出现错误之后,程序完全没必要继续运行下去了。

    GetUser 找不到记录的话,应该返回 nil 指针附带一个错误,指明发生了什么(比如是什么导致无法获取用户的,是没有记录,服务器挂了,服务器拒绝处理还是其他什么)。你可以参考 Google 在自己 AppEngine 系统上的实现:
    https://cloud.google.com/appengine/docs/go/datastore/reference#variables

    当 Datastore 尝试获取一个不存在的对象时,会返回 ErrNoSuchEntity 这个 error 。
    aphasia
        22
    aphasia  
       2016-07-29 23:51:59 +08:00
    这个跟你业务场景,以及设计有关,建议用 2 ,否则给自己留坑,不信你试试
    如果用 2 的话,可以在调用函数时区分出到底是同 db 交互失败,还是交互成功但却查询为空,可以在调用时区别地对待这两种结果……
    不信你试试 1 ……
    julor
        23
    julor  
       2016-07-30 07:44:11 +08:00 via Android
    查询结果为空,返回 not found ,与数据交互出现的无知,直接返回上级错误
    janxin
        24
    janxin  
       2016-07-30 09:50:57 +08:00 via iPhone
    @aphasia 这两种在区分功能上并没有区别吧
    darasion
        25
    darasion  
       2016-08-01 08:27:04 +08:00
    我认为,
    如果系统其他部分可能会报错,比如数据库可能连接不上, cache 可能挂了什么的,那返回值就需要第二个 error 参数
    如果系统其他部分根本不可能报错,就是一个普普通通的数据类型,没有跟其他系统交互,那么就没有第二个 error 返回,找不到就直接一个 nil 就好了, nil 本身就是找不到的意思,互为充分必要条件。
    至于返回是否是 nil 的检查,我想应该适当的抛给上层逻辑来处理。具体情况具体分析。
    leedstyh
        26
    leedstyh  
       2016-08-01 17:04:16 +08:00
    我也纠结过,现在的做法是:

    定义一个`UserNotFound`的空 User struct ,如果查询没有结果,就返回`UserNotFound, nil`。

    给 User 这个 struct 定义一个`IsNil()`的方法,一般来说用户名不能为空,所以就根据用户名来判断这个 user 是不是存在

    handler 里,如果`user.IsNil()`结果是 true ,就返回 404
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   937 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 21:50 · PVG 05:50 · LAX 13:50 · JFK 16:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.