我遇到一个if
语句遇到麻烦,该语句包括一个if
子句的前面语句部分的条件。
在这个简化的示例中,我想将ID扩展为按名称查找,也将名称扩展为首选前缀。
伪代码为:
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
在bash中很简单:
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
但是如何表达呢?
这是错误的:
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
}
我正在猜测,因为&&
序列的中间部分是语句,而不是表达式(与C不同)。
我尝试使用=
而不是:=
,并且将err
和g
声明为超出范围,但这无济于事。
我尝试过以下恐怖活动:
if if PREFIX != "" { n, err := GetByName(PREFIX + ":" + id) } ; err == nil {
但是该错误比n
和err
的作用域范围错误大, go 声称尽管我在if
之后仍希望有表达式试图给它一个由if组成的前面的语句
由于PREFIX
上的前导条件为非空,因此我无法轻易地将此if条件转换为使用前面的语句。如果上半部分不执行或上半部失败,我希望下半部分执行。
这里有有用的 go 惯用语吗?
我可以将代码分解为与sin *一样丑陋,带有重复的块,但是我正在寻找一个很好的惯用答案。
*我的意思是丑陋的,因为有两个else if
子句。
答案 0 :(得分:2)
更清洁的解决方案是定义一个辅助函数:
func getId(prefix string, name string) (int, error) {
if (prefix != "") {
if n, err := GetByName(prefix + ":" + name); err == nil {
return n.ID, nil
}
}
return GetByName(name)
}
并调用该函数:
if newId, err := getId(prefix, name) {
id = newId
}
答案 1 :(得分:1)
您不能使用单个if
语句来执行此操作,因此请使用其中两个。并且您可以使用“状态”变量来跟踪第一次查找是否成功:
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
}
}
如果创建辅助功能,则可以使原始任务更加紧凑。对该实用程序功能进行映像:
func lookup(name string, id *string) (ok bool) {
if n, err := GetByName(name); err == nil {
*id = n.ID
return true
}
return false
}
有了这个,您的原始任务将是:
_ = PREFIX != "" && lookup(PREFIX+":"+id, &id) || lookup(id, &id)
上一行的正确性基于布尔逻辑的短路评估。也就是说,如果PREFIX
为非空且第一次查找成功,则不会调用第二次查找。如果PREFIX
为空或第一次查找“失败”,则将调用第二次查找。
尽管第二个版本非常紧凑,但我仍然会选择第一个更详细但更干净的解决方案。最终,您的目标不是编写最紧凑的代码,而是编写最易读,最易维护的代码。