dongshanyan0322 2018-10-11 12:15
浏览 49

以if子句的前面语句为条件

I'm having trouble with an if statement that includes a conditional on the preceding statement part of the if clause.

In this simplified example, I want to extend a lookup by id to also lookup by name, with an optional prefix to be preferred.

The psuedo code is:

IF I have a prefix AND I can find a record using the prefix and name
THEN override the record ID
ELSE IF I can find a record using name
THEN override the record ID
ELSE do something else to override the record ID

In bash it would be simple:

if test -n "$PREFIX" && id_=$(GetByName "$PREFIX:$id")
then id="$id_"
elif id_=$(GetByName "$id")
then id="$id_"
elif id_=$(legacy_attempt "$id")
then id="$id_"
fi

But how to express this in go?

This is wrong:

if PREFIX != "" && n, err := GetByName(PREFIX + ":" + id) && err == nil {
    id = n.ID
} else if n, err := GetByName(id) && err == nil {
    id = n.ID
} else if n, err := legacy_attempt(id) && err == nil {
    id = n
}

I'm guessing because the middle portion of the && sequence is a statement, not an expression (unlike C).

I've tried with = instead of := and having err and g declared out of scope but it doesn't help.

I tried such horrors as:

if if PREFIX != "" { n, err := GetByName(PREFIX + ":" + id) } ; err == nil {

but the errors were more than the scoping errors of n and err, go claimed that it was expecting an expression after the if although I was trying to give it a preceding statement consisting of an if

Because of the leading conditional on PREFIX being non-empty I can't easily convert this if condition to use a preceding statement. I want the second half to execute if the first half doesn't execute or if the first half fails.

Are there any useful go idioms to help here?

I can factor the code out to be as ugly as sin*, with repeated blocks, but I'm looking for a nice idiomatic answer.

*And I mean ugly because of the two else if clauses.

  • 写回答

2条回答 默认 最新

  • dtuzjzs3853 2018-10-11 12:30
    关注

    You can't do this with a single if statement, so use 2 of them. And you may use a "state" variable to track if the first lookup succeeds:

    found := false
    if PREFIX != "" {
        if n, err := GetByName(PREFIX + ":" + id); err == nil {
            id, found  = n.ID, true
        }
    }
    if !found {
        if n, err := GetByName(id); err == nil {
            id = n.ID
        }
    }
    

    If you create a helper function, you can make your original task more compact. Image this utility function:

    func lookup(name string, id *string) (ok bool) {
        if n, err := GetByName(name); err == nil {
            *id = n.ID
            return true
        }
        return false
    }
    

    With this, your original task will be:

    _ = PREFIX != "" && lookup(PREFIX+":"+id, &id) || lookup(id, &id)
    

    Correctness of the above line builds on the short-circuit evaluation of the bool logic. That is, if PREFIX is non-empty and the first lookup succeeds, the second lookup will not be called. If PREFIX is empty or the first lookup "fails", the second lookup will be called.

    Even though this 2nd version is very compact, I'd still go with the first, more verbose but more clean solution. Ultimately you're goal is not to write the most compact code, but the most readable, most maintainable code.

    评论

报告相同问题?

悬赏问题

  • ¥20 求个正点原子stm32f407开发版的贪吃蛇游戏
  • ¥15 正弦信号发生器串并联电路电阻无法保持同步怎么办
  • ¥15 划分vlan后,链路不通了?
  • ¥20 求各位懂行的人,注册表能不能看到usb使用得具体信息,干了什么,传输了什么数据
  • ¥15 个人网站被恶意大量访问,怎么办
  • ¥15 Vue3 大型图片数据拖动排序
  • ¥15 Centos / PETGEM
  • ¥15 划分vlan后不通了
  • ¥20 用雷电模拟器安装百达屋apk一直闪退
  • ¥15 算能科技20240506咨询(拒绝大模型回答)