D语言中的表达式(一)

表达式

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 || AndAndExpression
OrOr 表达式的返回类型是布尔型,例外是当右边的操作数为 void 时,结果会是 void 型。

OrOr 表达式计算它左面的操作数。如果左面操作数在转型到布尔型后,结果为真,就不会计算右面的操作数。如果 OrOr 表达式结果的类型是布尔型,则表达式的结果就为真。如果左面操作数为假,就计算右面的操作数。如果 OrOr 表达式是布尔型的,则结果就是右面的操作数转型为布尔型后的结果。

AndAnd 表达式

	AndAnd表达式 && Or表达式
	AndAndExpression && OrExpression
	
AndAnd 表达式的返回类型是布尔型,例外是当右边的操作数为 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 RelExpression
	
is 用于比较同一性。如果要比较非同一性,使用 !(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 未定义或等于
注意:
  1. 对于浮点数比较运算符来说,(a !op b) 并不等价于 !(a op b) 。
  2. “未定义”的意思是有操作数为 NAN 。
  3. “异常”的意思是如果有操作数是 NAN ,则抛出 Invalid 异常。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值