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

    文章

    1624

    浏览量

    49112
  • 运算符
    +关注

    关注

    0

    文章

    172

    浏览量

    11082

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

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

收藏 人收藏

    评论

    相关推荐

    C语言运算符的使用方法

    详细介绍了C语言表达式、算术运算符、赋值运算符、关系运算符、条件结构、逻辑运算符、位运算符的语法和使用方法,并讨论了
    发表于 11-02 11:30 1606次阅读
    C语言<b class='flag-5'>运算符</b>的使用方法

    如何去使用运算符

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

    条件运算符是什么_条件运算符有哪些

    运算符优先级高于赋值、逗号运算符,低于其他运算符。关系运算实际上是逻辑比较运算,它是逻辑运算
    发表于 11-16 16:02 1.1w次阅读
    条件<b class='flag-5'>运算符</b>是什么_条件<b class='flag-5'>运算符</b>有哪些

    单目运算符是什么_单目运算符有哪些

    单目运算符是指运算所需变量为一个的运算符,又叫一运算符,其中有逻辑非运算符:!、按位取反
    的头像 发表于 02-24 15:42 6.1w次阅读
    单目<b class='flag-5'>运算符</b>是什么_单目<b class='flag-5'>运算符</b>有哪些

    C运算符的优先级和结合性详细解决

    运算符是一种告诉编译器执行特定的数学或逻辑操作的符号。 C语言内置了丰富的运算符,大体可分为10类:算术运算符、关系运算符、逻辑运算符、位
    的头像 发表于 02-22 17:27 3234次阅读

    浅析MySQL中的各类运算符

    MySQL支持多种运算符,我们在写SQL脚本时经常会需要用到各种各样的运算符,这些运算符可以用来连接表达式,进而从数据库中查询我们需要的结果集等。这些类型主要包括算术运算符、比较
    的头像 发表于 05-03 17:41 2054次阅读
    浅析MySQL中的各类<b class='flag-5'>运算符</b>

    干货:大实例讲解种C++运算符重载

    本章节主要讲解是运算符重载。运算符重载是赋予运算符能操作自定义类型的功能。C++运算符重载主要分为以下类:
    的头像 发表于 09-30 16:59 3440次阅读
    干货:<b class='flag-5'>三</b>大实例讲解<b class='flag-5'>三</b>种C++<b class='flag-5'>运算符</b>重载

    python运算符是什么

    python运算符 0. 什么是运算符? 本章节主要说明Python的运算符。举个简单的例子 4 +5 = 9 。 例子中,4和5被称为操作数,“+”号为运算符。 Python语言支持
    的头像 发表于 02-21 16:44 2378次阅读

    SystemVerilog-运算符/表达式规则

    RTL建模中广泛使用的运算符是条件运算符,也称为三元运算符,该运算符用于在两个表达式之间进行选择——表5-2列出了用于表示条件
    的头像 发表于 08-03 09:03 3113次阅读

    如何灵活使用三元运算符

    给定四个无符号数,请找出最小值。无符号数可以与标准比较运算符(a < b)进行比较。使用条件运算符描述一个两路的最小值电路,然后组合它来创建一个4路最小电路。可能需要一些线向量作为中间结果。
    的头像 发表于 09-28 17:07 1294次阅读

    什么是运算符重载

    重载运算符是具有特殊名称的函数,是通过关键字** operator **后跟运算符的符号来定义的
    的头像 发表于 01-20 15:30 2487次阅读

    条件(三元运算符

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

    什么是移位运算符

    移位运算符将向量的位向右或向左移位指定的次数。SystemVerilog具有按位和算术移位运算符
    的头像 发表于 02-09 15:49 1831次阅读
    什么是移位<b class='flag-5'>运算符</b>

    Go语言运算符主要包括哪些呢?

    Go语言运算符主要包括:算数运算符、关系运算符、逻辑运算符、位运算符、赋值运算符和其他
    的头像 发表于 05-26 15:54 862次阅读
    Go语言<b class='flag-5'>运算符</b>主要包括哪些呢?

    c语言从右到左的运算符有哪些

    用在变量之后时,它们会先返回变量的原始值,然后再进行递增或递减。 三元条件运算符 ( ?: ):这个运算符的求值顺序是从右到左。首先计算第个表达式,然后根据第一个表达式的结果选择第二
    的头像 发表于 08-20 11:39 918次阅读