表达式
C 和 C++ 程序员会发现 D 中的表达式很熟悉,另外还有一些有意思的扩充。表达式用来计算多个值并返回一个特定类型的值。随后,所得的值可以被用于赋值、测试或被忽略。表达式也可能有副作用。
表达式: 赋值表达式 赋值表达式 , 表达式 赋值表达式: 条件表达式 条件表达式 = 赋值表达式 条件表达式 += 赋值表达式 条件表达式 -= 赋值表达式 条件表达式 *= 赋值表达式 条件表达式 /= 赋值表达式 条件表达式 %= 赋值表达式 条件表达式 &= 赋值表达式 条件表达式 |= 赋值表达式 条件表达式 ^= 赋值表达式 条件表达式 ~= 赋值表达式 条件表达式 <<= 赋值表达式 条件表达式 >>= 赋值表达式 条件表达式 >>>= 赋值表达式 条件表达式: OrOr表达式 OrOr表达式 ? 表达式 : 条件表达式 OrOr表达式: AndAnd表达式 OrOr表达式 || AndAnd表达式 AndAnd表达式: 或表达式 AndAnd表达式 && 或表达式 或表达式: 异或表达式 或表达式 | 异或表达式 异或表达式: 与表达式 异或表达式 ^ 与表达式 与表达式: 相等表达式 与表达式 & 相等表达式 相等表达式: 关系表达式 相等表达式 == 关系表达式 相等表达式 != 关系表达式 相等表达式 is 关系表达式 关系表达式: 移位表达式 关系表达式 < 移位表达式 关系表达式 <= 移位表达式 关系表达式 > 移位表达式 关系表达式 >= 移位表达式 关系表达式 !<>= 移位表达式 关系表达式 !<> 移位表达式 关系表达式 <> 移位表达式 关系表达式 <>= 移位表达式 关系表达式 !> 移位表达式 关系表达式 !>= 移位表达式 关系表达式 !< 移位表达式 关系表达式 !<= 移位表达式 关系表达式 in 移位表达式 移位表达式: 和表达式 移位表达式 << 和表达式 移位表达式 >> 和表达式 移位表达式 >>> 和表达式 和表达式: 积表达式 和表达式 + 积表达式 和表达式 - 积表达式 和表达式 ~ 积表达式 积表达式: 一元表达式 积表达式 * 一元表达式 积表达式 / 一元表达式 积表达式 % 一元表达式 一元表达式: 后缀表达式 & 一元表达式 ++ 一元表达式 -- 一元表达式 * 一元表达式 - 一元表达式 + 一元表达式 ! 一元表达式 ~ 一元表达式 delete 一元表达式 New表达式 cast ( 类型 ) 一元表达式 ( 类型 ) . 标志符 ( 表达式 ) 后缀表达式: 基本表达式 后缀表达式 . 标志符 后缀表达式 ++ 后缀表达式 -- 后缀表达式 ( 参数列表 ) 索引表达式 切片表达式 索引表达式: 后缀表达式 [ 参数列表 ] 切片表达式: 后缀表达式 [ 赋值表达式 .. 赋值表达式 ] 基本表达式: 标志符 .标志符 this super null true false 数值文字量 字符文字量 字符串文字量 函数文字量 断言表达式 基本类型 . 标志符 typeid ( 类型 ) 断言表达式: assert ( 表达式 ) 参数列表: 赋值表达式 赋值表达式 , 参数列表 New表达式: new 基本类型 Stars [ 赋值表达式 ] 声明符 new 基本类型 Stars ( 参数列表 ) new 基本类型 Stars new ( 参数列表 ) 基本类型 Stars [ 赋值表达式 ] 声明符 new ( 参数列表 ) 基本类型 Stars ( 参数列表 ) new ( 参数列表 ) 基本类型 Stars Stars nothing * * Stars
Expression: AssignExpression AssignExpression , Expression AssignExpression: ConditionalExpression ConditionalExpression = AssignExpression ConditionalExpression += AssignExpression ConditionalExpression -= AssignExpression ConditionalExpression *= AssignExpression ConditionalExpression /= AssignExpression ConditionalExpression %= AssignExpression ConditionalExpression &= AssignExpression ConditionalExpression |= AssignExpression ConditionalExpression ^= AssignExpression ConditionalExpression ~= AssignExpression ConditionalExpression <<= AssignExpression ConditionalExpression >>= AssignExpression ConditionalExpression >>>= AssignExpression ConditionalExpression: OrOrExpression OrOrExpression ? Expression : ConditionalExpression OrOrExpression: AndAndExpression OrOrExpression || AndAndExpression AndAndExpression: OrExpression AndAndExpression && OrExpression OrExpression: XorExpression OrExpression | XorExpression XorExpression: AndExpression XorExpression ^ AndExpression AndExpression: EqualExpression AndExpression & EqualExpression EqualExpression: RelExpression EqualExpression == RelExpression EqualExpression != RelExpression EqualExpression is RelExpression RelExpression: ShiftExpression RelExpression < ShiftExpression RelExpression <= ShiftExpression RelExpression > ShiftExpression RelExpression >= ShiftExpression RelExpression !<>= ShiftExpression RelExpression !<> ShiftExpression RelExpression <> ShiftExpression RelExpression <>= ShiftExpression RelExpression !> ShiftExpression RelExpression !>= ShiftExpression RelExpression !< ShiftExpression RelExpression !<= ShiftExpression RelExpression in ShiftExpression ShiftExpression: AddExpression ShiftExpression << AddExpression ShiftExpression >> AddExpression ShiftExpression >>> AddExpression AddExpression: MulExpression AddExpression + MulExpression AddExpression - MulExpression AddExpression ~ MulExpression MulExpression: UnaryExpression MulExpression * UnaryExpression MulExpression / UnaryExpression MulExpression % UnaryExpression UnaryExpression: PostfixExpression & UnaryExpression ++ UnaryExpression -- UnaryExpression * UnaryExpression - UnaryExpression + UnaryExpression ! UnaryExpression ~ UnaryExpression delete UnaryExpression NewExpression cast ( Type ) UnaryExpression ( Type ) . Identifier ( Expression ) PostfixExpression: PrimaryExpression PostfixExpression . Identifier PostfixExpression ++ PostfixExpression -- PostfixExpression ( ArgumentList ) IndexExpression SliceExpression IndexExpression: PostfixExpression [ ArgumentList ] SliceExpression: PostfixExpression [ AssignExpression .. AssignExpression ] PrimaryExpression: Identifier .Identifier this super null true false NumericLiteral CharacterLiteral StringLiteral FunctionLiteral AssertExpression BasicType . Identifier typeid ( Type ) AssertExpression: assert ( Expression ) ArgumentList: AssignExpression AssignExpression , ArgumentList NewExpression: new BasicType Stars [ AssignExpression ] Declarator new BasicType Stars ( ArgumentList ) new BasicType Stars new ( ArgumentList ) BasicType Stars [ AssignExpression ] Declarator new ( ArgumentList ) BasicType Stars ( ArgumentList ) new ( ArgumentList ) BasicType Stars Stars nothing * * Stars
求值顺序
除非另外指定(如 or 或者 and 运算那样),D 的实现可以以任何顺序对表达式中的各个部分求值。如果没有额外指定,就不能依赖于求值的顺序。例如,下面的代码是非法的:i = ++i; c = a + (a = b); func(++i, ++i);如果编译器能够确定表达式的值是依赖于求值顺序的话,它将报告一个错误(但这不是必须的)。检测这种错误的能力是实现的质量方面的问题。
表达式
赋值表达式 , 表达式
AssignExpression , Expression先计算‘ ,’左面的操作数,然后计算右面的操作数。表达式的类型是右面的操作数的类型,表达式的结果是右面的操作数的结果。
赋值表达式
条件表达式 = 赋值表达式
ConditionalExpression = AssignExpression右面操作数的类型会被隐式地转换为左面操作数的类型,并赋给左面的操作数。结果的操作数的类型是左值得类型,结果的值是赋值后左值的值。
左面的操作数必须是左值。
赋值运算符表达式
条件表达式 += 赋值表达式 条件表达式 -= 赋值表达式 条件表达式 *= 赋值表达式 条件表达式 /= 赋值表达式 条件表达式 %= 赋值表达式 条件表达式 &= 赋值表达式 条件表达式 |= 赋值表达式 条件表达式 ^= 赋值表达式 条件表达式 <<= 赋值表达式 条件表达式 >>= 赋值表达式 条件表达式 >>>= 赋值表达式
ConditionalExpression += AssignExpression ConditionalExpression -= AssignExpression ConditionalExpression *= AssignExpression ConditionalExpression /= AssignExpression ConditionalExpression %= AssignExpression ConditionalExpression &= AssignExpression ConditionalExpression |= AssignExpression ConditionalExpression ^= AssignExpression ConditionalExpression <<= AssignExpression ConditionalExpression >>= AssignExpression ConditionalExpression >>>= AssignExpression赋值运算符表达式,如:
a op= b在语义上等价于:
a = a op b差别是操作数 a 只计算一次。
条件表达式
OrOr表达式 ? 表达式 : 条件表达式
OrOrExpression ? Expression : ConditionalExpression第一个表达式会被转换为布尔型,并被计算。如果结果为真,就计算第二个表达式,所得到的结果就是条件表达式的结果。如果结果为假,就计算第三个表达式,所得到的结果就是条件表达式的结果。如果第二个或者第三个表达式是 void 型的,返回的类型就是 void 。否则,第二个和第三个表达式的类型会被隐式地转换为一个它们的公共类型,并成为条件表达式结果的类型。
OrOr 表达式
OrOr表达式 || AndAnd表达式
OrOrExpression || AndAndExpressionOrOr 表达式的返回类型是布尔型,例外是当右边的操作数为 void 时,结果会是 void 型。
OrOr 表达式计算它左面的操作数。如果左面操作数在转型到布尔型后,结果为真,就不会计算右面的操作数。如果 OrOr 表达式结果的类型是布尔型,则表达式的结果就为真。如果左面操作数为假,就计算右面的操作数。如果 OrOr 表达式是布尔型的,则结果就是右面的操作数转型为布尔型后的结果。
AndAnd 表达式
AndAnd表达式 && Or表达式
AndAndExpression && OrExpressionAndAnd 表达式的返回类型是布尔型,例外是当右边的操作数为 void 时,结果会是 void 型。
AndAnd 表达式计算它左面的操作数。如果左面操作数在转型到布尔型后,结果为假,就不会计算右面的操作数。如果 AndAnd 表达式结果的类型是布尔型,则表达式的结果就为假。如果左面操作数为真,就计算右面的操作数。如果 AndAnd 表达式是布尔型的,则结果就是右面的操作数转型为布尔型后的结果。
按位表达式
按位表达式对它们的操作数按位运算。它们的操作数必须是正数类型的。首先,会应用默认的正数提升。然后,执行按位运算。Or 表达式
或表达式 | 异或表达式
OrExpression | XorExpression操作数之间执行‘或’运算。
Xor 表达式
异或表达式 ^ 与表达式
XorExpression ^ AndExpression操作数之间执行‘异或’运算。
And 表达式
与表达式 & 相等表达式
AndExpression & EqualExpression操作数之间执行‘与’运算。
相等表达式
相等表达式 == 关系表达式 相等表达式 != 关系表达式 相等表达式 is 关系表达式
EqualExpression == RelExpression EqualExpression != RelExpression EqualExpression is RelExpression相等表达式比较相等运算符( ==)或不等运算符( !=)的两个操作数。结果的类型是布尔型。在比较之前,操作数会通过常用的转换转型为它们的一个公共类型。
如果操作数是整数值或者指针,相等被定义按位精确匹配。结构的相等是指按位精确匹配(检查包括由于对齐而造成的空洞,通常它们会在初始化时被设为零)。浮点数的相等更复杂。-0 和 +0 相等。如果两个操作数都是 NAN ,则 == 和 != 运算都会返回假。其他情况下,按位比较相等性。
对于复数来说,相等被定义为等价于:
x.re == y.re && x.im == y.im不相等被定义为等价于:
x.re != y.re || x.im != y.im对于类对象而言,相等被定义为调用 Object.eq() 的结果。如果有对象为 null ,会抛出异常。
至于静态和动态数组,相等被定义为数组长度相等,并且对应的元素都相等。
同一表达式
相等表达式 is 关系表达式
EqualExpression is RelExpressionis 用于比较同一性。如果要比较非同一性,使用 !(e1 is e2) 。结果的类型是布尔型。在比较之前,操作数会通过常用的转换转型为它们的一个公共类型。
如果操作数不是类对象、静态或动态数组,同一性被定义为等价于相等性。
对于类对象来说,同一性被定义为引用指向同一个对象。可以使用 is 比较 null 类对象。
对于静态和动态数组来说,同一性被定义为指向相同的数组元素。
同一运算符 is 不能被重载。
关系表达式
关系表达式 < 移位表达式 关系表达式 <= 移位表达式 关系表达式 > 移位表达式 关系表达式 >= 移位表达式 关系表达式 !<>= 移位表达式 关系表达式 !<> 移位表达式 关系表达式 <> 移位表达式 关系表达式 <>= 移位表达式 关系表达式 !> 移位表达式 关系表达式 !>= 移位表达式 关系表达式 !< 移位表达式 关系表达式 !<= 移位表达式 关系表达式 in 移位表达式
RelExpression < ShiftExpression RelExpression <= ShiftExpression RelExpression > ShiftExpression RelExpression >= ShiftExpression RelExpression !<>= ShiftExpression RelExpression !<> ShiftExpression RelExpression <> ShiftExpression RelExpression <>= ShiftExpression RelExpression !> ShiftExpression RelExpression !>= ShiftExpression RelExpression !< ShiftExpression RelExpression !<= ShiftExpression RelExpression in ShiftExpression首先,会对操作数应用整数提升。关系表达式返回结果的类型是布尔型。
对于类对象来说,Object.cmp() 的结果构成了左操作数,0 构成了右操作数。关系表达式 (o1 op o2) 的结果是:
(o1.cmp(o2) op 0)如果对象为 null,进行比较就是错误。
对于静态和动态数组来说,关系 op 的结果是操作符应用到数组中第一个不相等的元素的结果。如果两个数组相等,但是长度不同,较短的数组“小于”较长的数组。
整数比较
如果两个操作数都是整数类型,就会进行整数比较。
运算符 | 关系 |
---|---|
< | 小于 |
> | 大于 |
<= | 小于等于 |
>= | 大于等于 |
== | 相等 |
!= | 不相等 |
如果 <、<=、> 或 >= 表达式中一个操作数为有符号数,另一个操作数为无符号数,会被视为错误。可以使用类型转换将两个操作数转型为同是有符号数或同是无符号数。
浮点数比较
如果有操作数是浮点数,则执行浮点数比较。任何有实用价值的浮点操作都必须支持 NAN 值。尤其关系运算符要支持 NAN 操作数。浮点数的关系运算的结果可以是小于、大于、等于或未定义(未定义的意思是有操作数为 NAN )。这意味着有 14 可能的比较条件:
运算符 | 大于 | 小于 | 等于 | 未定义 | 异常 | 关系 |
---|---|---|---|---|---|---|
== | F | F | T | F | no | 等于 |
!= | T | T | F | T | no | 未定义、小于或大于 |
> | T | F | F | F | yes | 大于 |
>= | T | F | T | F | yes | 大于等于 |
< | F | T | F | F | yes | 小于 |
<= | F | T | T | F | yes | 小于等于 |
!<>= | F | F | F | T | no | 未定义 |
<> | T | T | F | F | yes | 小于或大于 |
<>= | T | T | T | F | yes | 小于,等于或大于 |
!<= | T | F | F | T | no | 未定义或大于 |
!< | T | F | T | T | no | 未定义、大于或等于 |
!>= | F | T | F | T | no | 未定义或小于 |
!> | F | T | T | T | no | 未定义、小于或等于 |
!<> | F | F | T | T | no | 未定义或等于 |
注意:
- 对于浮点数比较运算符来说,(a !op b) 并不等价于 !(a op b) 。
- “未定义”的意思是有操作数为 NAN 。
- “异常”的意思是如果有操作数是 NAN ,则抛出 Invalid 异常。