0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Golang为何舍弃三元运算符

马哥Linux运维 来源:cnblogs 2024-04-03 15:13 次阅读

三元运算符广泛存在于其他语言中,比如:

python

val = trueValue if expr else falseValue

javascript:

const val = expr ? trueValue : falseValue

c、c++

const char *val = expr ? "trueValue" : "falseValue";

然而,被广泛支持的三目运算符在golang中却是不存在的!如果我们写出类似下面的代码:

val := expr ? "trueValue" : "falseValue"

那么编译器就该抱怨了:invalid character U+003F '?'。意思是golang中不存在?这个运算符,编译器不认识而且非字母数字下划线也不能用做变量名,自然也就当作是非法字符了。

然而这是为什么呢,其实官方给出了解释,这里简单引用一下:

The reason ?: is absent from Go is that the language's designers had seen the operation used too often to create impenetrably complex expressions. The if-else form, although longer, is unquestionably clearer. A language needs only one conditional control flow construct.

golang中不存在?:运算符的原因是因为语言设计者已经预见到三元运算符经常被用来构建一些极其复杂的表达式。虽然使用if进行替代会让代码显得更长,但这毫无疑问可读性更强。一个语言只需要有一种条件判断结构就足够了。

毫无疑问,这是在golang“大道至简”的指导思想下的产物。

这段话其实没问题,因为某些三元运算符的使用场景确实会降低代码的可读性:

const status = (type===1?(agagin===1?'再售':'已售'):'未售')
const word = (res.distance === 0) ? 'a'
: (res.distance === 1 && res.difference > 3) ? 'b'
: (res.distance === 2 && res.difference > 5 && String(res.key).length > 5) ? 'c'
: 'd';

乍一看确实很复杂,至少第二个表达式不花个20秒细看可能没法理清控制流程(想象一下当缩进错位或是完全没有缩进的时候)。

如果把它们直接转化成if语句是这样的:

let status = ''
if (type === 1) {
if (again === 1) {
status = '再售'
} else {
status = '已售'
}
} else {
status = '未售'
}
let word = ''
if (res.distance === 0) {
word = 'a'
} else {
if (res.distance === 1 && res.difference > 3) {
word = 'b'
} else {
if (res.distance === 2 && res.difference > 5 && String(res.key).length > 5) {
word = 'c'
} else {
word = 'd'
}
}
}

看起来并没有多少的改善,特别是例2,三层嵌套,不管是谁review到这段代码难免不会抱怨你几句。

然而事实上这些代码是可以简化的,考虑到三元运算符总是会给变量一个值,因此最后的else其实可以看作是变量的默认值,于是代码可以这么写:

let status = '未售'
if (type === 1) {
if (again === 1) {
status = '再售'
} else {
status = '已售'
}
}
let word = 'd'
if (res.distance === 0) {
word = 'a'
} else {
if (res.distance === 1 && res.difference > 3) {
word = 'b'
} else {
if (res.distance === 2 && res.difference > 5 && String(res.key).length > 5) {
word = 'c'
}
}
}

其次,对于例2,显然可以使用else if来清除嵌套结构:

let word = 'd'
if (res.distance === 0) {
word = 'a'
} else if (res.distance === 1 && res.difference > 3) {
word = 'b'
} else if (res.distance === 2 && res.difference > 5 && String(res.key).length > 5) {
word = 'c'
}

现在再来看,显然使用if语句的版本的可读性更高,逻辑也更清晰(通过去除嵌套)。

然而事实也不尽然。除了用三元运算符表达流程控制之外,事实上更常见更广泛的一个应用是如下这样的表达式:

const val = expr ? trueValue : falseValue
const func = (age) => age > 18 ? '成年人' : '未成年人'

类似上述通过一个简短的条件表达式来确定变量的值,在开发中的出现频率是相当高的。这时三元运算符的意图更清晰,可读性也较if语句更高,特别是配合匿名函数(lambda表达式)使用可以极大简化我们的代码。

对此python的解决之道是之支持上述的简化版三元表达式,同时表达式不支持嵌套,达到了扬长避短的目的。不过代价是编译器的相关实现会复杂化。

而对于golang来说一个简单的能只通过单遍扫描即可完成ast构建的编译器是其保持急速的构建速度的秘诀之一,为了这样简单的功能增加编译器实现的复杂度是不可接受的。同时由于golang“大道至简”的哲学,能用现有语法结构解决的问题,自然不会再添加新的语法。

不过还是有办法的,虽然不推荐

func If(cond bool, a, b interface{}) {
if cond {
return a
}
return b
}
age := 20
val := If(age > 18, "成年人", "未成年人").(string)

不推荐这么做是有几个原因:

使用接口导致性能下降

需要强制的类型断言

不管三元表达式还是if语句,对于不会到达的分支是不会计算的,也就是惰性计算;而给函数传递参数时每一个表达式都会被计算

最后总结一下:

三元运算符的优点:

对于简短的表达式使用三元运算符表意更清晰,特别是在习惯了线性阅读三元运算符表达式之后

不需要中间状态(例如第一个例子中的let变量可以替换为const,代码更健壮),心智负担更低

没有中间状态也就意味着更少或完全没有副作用,代码更易跟踪和维护

但三元运算符也有明显的缺点:

对于复杂逻辑代码可读性较差(例如第一个例子中的status,需要在trueValue的位置进行进一步的条件判断时)

容易被滥用,很多人将其用于替代if语句或是简化复杂的if嵌套,这会导致上一条中所描述的结果

条件分支只能为表达式,不支持多条语句

所以这是一个见仁见智的问题,总之只能入乡随俗了。

审核编辑:黄飞

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 编译器
    +关注

    关注

    1

    文章

    1577

    浏览量

    48629
  • 运算符
    +关注

    关注

    0

    文章

    163

    浏览量

    10948

原文标题:为什么golang中不存在三元运算符

文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Verilog 缩减运算符

    小弟刚学FPGA ,在看Veriolg ,遇到缩减运算符,对于缩减与 缩减或能理解,那个非本身就是单目运算,缩减非是怎么回事呢?
    发表于 10-07 10:13

    炼狱传奇-移位和位拼运算符之战

    运算符,就会使程序编写起来变得简单了。代码的意思就是,每次把最低位放到最高位,让前位放到后面,这样逻辑“1”就实现了移位,形成了循环。
    发表于 04-30 09:43

    C语言运算符的优先级和结合性

    ;、a=c=d;等。 3) 像 +、-、*、/ 这样的运算符,它的两边都有数据,例如 3+4、a*3 等,有两个操作数,我们称这样的运算符为双目运算符。后面还会讲解单目运算符
    发表于 07-06 06:46

    【FPGA】VHDL 语言的运算符有哪些?计算的优先级是怎样的?

    注意的是乘方(**)运算的右边必须为整数。VHDL 的算术运算符如表 2-8 所示。4.移位运算符移位运算符为二
    发表于 09-12 09:51

    【梦翼师兄今日分享】 常见的关系运算符(移位运算符)

    立即学习>>梦翼师兄FPGA培训(视频加板卡),手把手带你入门FPGA写在前面的话移位运算符是双目运算符,将运算符左边的操作数左移或右移指定的位数,用0来补充空闲位。如果右边操作数的值
    发表于 12-17 10:45

    【梦翼师兄今日分享】 常见的关系运算符(缩减运算符

    立即学习>>梦翼师兄FPGA培训(视频加板卡),手把手带你入门FPGA写在前面的话缩减运算符是单目运算符,也有与或非运算。其与或非运算规则类似于位
    发表于 12-17 10:48

    【梦翼师兄今日分享】 常见的关系运算符(位拼运算符

    立即学习>>梦翼师兄FPGA培训(纯视频),手把手带你入门FPGA写在前面的话位拼运算符是将多个小的表达式合并形成一个大的表达式,用符号{}来实现多个表达式的连接运算,各个表达式之间用
    发表于 12-19 09:38

    C语言运算符优先级(超详细)

    C语言运算符优先级(超详细) 当想找哪个运算符优先级高时,很多时候总是想找的就没有,真让人气愤!现在,终于有个我个人觉得非常全的,分享给大家,欢迎拍砖!C语言运算符优先级[table]优先级
    发表于 04-27 16:47

    Java基础之Java运算符

    在Java中,表达式是由运算符和操作数组成的。比如,我们可以把下面的都称为表达式:5num1num1+num2sum=num1+num2Java的运算符包括:算术运算符、赋值运算符、关
    发表于 05-18 15:39

    如何去使用运算符

    运算的定义是什么?运算符是由什么组成的?如何去使用运算符
    发表于 07-15 13:13

    C语言中运算符? :怎么使用?

    C语言中运算符? :怎么使用?
    发表于 11-02 09:23

    算术运算符的相关资料分享

    一:算术运算符算术运算符非常地简单,就是小学数学里面的一些加减乘除操作。不过呢,还是有一些语法细节需要注意的。1.加法运算符 + 1 在第3行利用加法运算符 + 进行了加法
    发表于 11-30 06:09

    运算符的相关资料推荐

    运算符1、算数操作运算符+、-、*、/、%加法:A+B, AB最好是同类型乘除:乘法在很多CPU中并不支持,乘除法能不用就不用,可能会使执行变差求模/求余数:n%m=res[0~(m-1)]求模
    发表于 12-24 06:13

    2.7 python运算符

    优先级的所有运算符:[table][td]运算符描述**指数 (最高优先级)~,+,-按位翻转, 一加号和减号 (最后两个的方法名为 +@ 和 -@)*,/,%,//乘,除,取模和取整除+,-加法减法
    发表于 02-21 16:43

    条件(三元运算符

    RTL建模中广泛使用的运算符是条件运算符,也称为三元运算符,该运算符用于在两个表达式之间进行选择——表5-2列出了用于表示条件
    的头像 发表于 02-09 15:42 1032次阅读
    条件(<b class='flag-5'>三元</b>)<b class='flag-5'>运算符</b>