分享
 
 
 

D语言中的表达式(二)

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

In 表达式关系表达式 in 移位表达式

RelExpression in ShiftExpression

可以检测一个元素是否在关联数组中:int foo[char[]];

……

if ("hello" in foo)

……

in 表达式同关系表达式 <、<= 等有相同的优先级。

移位表达式移位表达式 << 和表达式

移位表达式 >> 和表达式

移位表达式 >>> 和表达式

ShiftExpression << AddExpression

ShiftExpression >> AddExpression

ShiftExpression >>> AddExpression

操作数必须是整数类型,并且会使用常用的整数提升。结果的类型是左操作数提升后的类型。结果的值是左操作数移动右操作数指定的位得到的值。

<< 是左移,>> 是有符号右移(译注:也叫算术右移)。>>> 是无符号右移。(译注:也叫逻辑右移)

如果要移动的位数超过了左操作数的位数,会被认为是非法的: int c;

c << 33;error

和表达式和表达式 + 积表达式

和表达式 - 积表达式

和表达式 ~ 积表达式

AddExpression + MulExpression

AddExpression - MulExpression

AddExpression ~ MulExpression

如果操作数是整数类型,会应用整数提升,然后会通过常用的算术转换提升为它们的公共类型。

如果有操作数为浮点类型,另一个操作数会被隐式地转换为浮点类型,然后会通过常用的算术转换提升为它们的公共类型。

如果运算符是 + 或 - ,第一个操作数是指针,并且第二个操作数是整数类型,结果的类型就是第一个操作数的类型,结果的值是指针加上(或减去)第二个操作数乘以指针所指类型的大小得到的值。

如果指针所指的类型是 bit ,结果的值是第二个操作数除以 8 后与指针相加得到的指。如果第二个操作数不能被 8 整除,会被视为非法。bit* p;

p += 1;// 错误,1%8 不等于零

p += 8;// ok

如果第二个操作数是指针,第一个操作数是整数类型,并且运算符是 + ,会按照上面所说的方式进行指针运算,只不过操作数的顺序反过来。

浮点操作数的和表达式不是可结合的。

积表达式积表达式 * 一元表达式

积表达式 / 一元表达式

积表达式 % 一元表达式

MulExpression * UnaryExpression

MulExpression / UnaryExpression

MulExpression % UnaryExpression

操作数必须是算术类型。先会执行整数提升,然后会通过常用的算术转换提升为它们的公共类型。

对于整数操作数来说,*、/ 和 % 对应于乘、除和取模运算。对于乘运算,会忽略溢出,结果会简单地截取为整数类型。如果除或者取模运算的右操作数为 0 ,会抛出一个 DivideByZero 异常。

对于浮点操作数来说,各种运算同对应的 IEEE 754 浮点运算相同。取模运算只能用于实数类型,不能用于虚数或者复数类型。

浮点数的积表达式不是可结合的。

一元表达式& 一元表达式

++ 一元表达式

-- 一元表达式

* 一元表达式

- 一元表达式

+ 一元表达式

! 一元表达式

~ 一元表达式

delete 一元表达式

New表达式

cast ( 类型 ) 一元表达式

( 类型 ) . 标志符

( 表达式 )

& UnaryExpression

++ UnaryExpression

-- UnaryExpression

* UnaryExpression

- UnaryExpression

+ UnaryExpression

! UnaryExpression

~ UnaryExpression

delete UnaryExpression

NewExpression

cast ( Type ) UnaryExpression

( Type ) . Identifier

( Expression )

New 表达式New 表达式用来在垃圾收集堆(默认情况)上或使用类指定的分配器分配内存。

在为多维数组分配内存时,声明按照同读取后缀数组声明顺序相同的顺序读取声明。 char[][] foo;// 字符串动态数组

...

foo = new char[][30];// 分配 30 个字符串数组

转型表达式在 C 和 C++ 中,类型转换的形式为:(类型) 一元表达式

(type) unaryexpression

但是,这会在语法上造成歧义。考虑:(foo) - p;

这是将负 p 转型为 foo ,还是 foo 减去 p ?如果不通过查找符号表以确定它究竟是一个类型还是一个变量,就不可能作出判断。但 D 的设计目标就是使语法为上下文无关的——应该无需检索符号表就能进行语法分析。所以,为了区分转型和带括号的字表达式,需要引入不同的语法。

C++ 通过引入:dynamic_cast<类型>(表达式)

dynamic_cast<type>(expression)

解决这个问题,但这写起来又丑陋又笨拙。D 引入了 cast 关键字:cast(foo) -p;// c将 (-p) 转型为 foo

(foo) - p;// foo 减去 p

cast 具有很好的性质,可以很容易地通过文本查找方式找到它,还会减轻那些被无情地重载的‘()’运算符的负担。

在转型的其他方面,D 同 C/C++ 也有所不同。任何从类引用到派生类引用的转换都会执行运行时检查以确保转型是适当的。这种行为等价于 C++ 中的 dynamic_cast 运算符。class A { ... }

class B : A { ... }

void test(A a, B b)

{

B bx = a;// 错误,需要类型转换

B bx = cast(B) a;// 如果 a 不是 B 类型,bx 就为 null

A ax = b;// 不需要类型转换

A ax = cast(A) b;// 不需要向上类型转换的运行时检查

}

如果想要检测一个对象 o 是否是类 B 的一个实例,可以使用转型:if (cast(B) o)

{

// o 是 B 的一个实例

}

else

{

// o 不是 B 的一个实例

}

后缀表达式后缀表达式 . 标志符

后缀表达式 -> 标志符

后缀表达式 ++

后缀表达式 --

后缀表达式 ( 参数列表 )

后缀表达式 [ 参数列表 ]

后缀表达式 [ 赋值表达式 .. 赋值表达式 ]

PostfixExpression . Identifier

PostfixExpression -> Identifier

PostfixExpression ++

PostfixExpression --

PostfixExpression ( ArgumentList )

PostfixExpression [ ArgumentList ]

PostfixExpression [ AssignExpression .. AssignExpression ]

索引表达式后缀表达式 [ 参数列表 ]

PostfixExpression [ ArgumentList ]

后缀表达式 会被计算。如果 后缀表达式 的类型为静态或者动态数组,会隐式地声明变量 length ,并将数组的长度赋给它。参数列表 有自己独立的声明作用域,length 只出现在这个作用域中。

切片表达式后缀表达式 [ 赋值表达式 .. 赋值表达式 ]

PostfixExpression [ AssignExpression .. AssignExpression ]

或缀表达式 会被计算。如果 后缀表达式 的类型为静态或者动态数组,会隐式地声明变量 length ,并将数组的长度赋给它。赋值表达式 有自己独立的声明作用域,length 和 赋值表达式 只出现在这个作用域中。

第一个 赋值表达式 是切片的闭的下界,第二个 赋值表达式 是切片的开的上界。(译注:也就是 [...) ,学过数学的都知道,呵呵)。表达式的结果是 后缀表达式 数组的一个切片。

基本表达式标志符

.标志符

this

super

null

true

false

数值文字量

字符文字量

字符串文字量

函数文字量

断言表达式

基本类型 . 标志符

typeid ( 类型 )

Identifier

.Identifier

this

super

null

true

false

NumericLiteral

CharacterLiteral

StringLiteral

FunctionLiteral

AssertExpression

BasicType . Identifier

typeid ( Type )

.标志符会在模块作用域内查找 标志符 ,而不是在当前词法的嵌套作用域内。

this在非静态成员函数内,this 是指向调用此函数的对象的指针。如果成员函数是显式地通过引用 typeof(this) 调用的,会生成一个非虚函数调用:class A

{

char get() { return 'A'; }

char foo() { return typeof(this).get(); }

char bar() { return this.get(); }

}

class B : A

{

char get() { return 'B'; }

}

void main()

{

B b = new B();

b.foo();// 返回 'A'

b.bar();// 返回 'B'

}

super在非静态成员函数内,super 是指向调用此函数的对象的指针,而这个指针被转换为它的基类类型的指针。如果不存在相应的基类,就会被认为是错误。super 不允许出现在结构的成员函数中。如果成员函数是显式地通过引用 super 调用的,会生成一个非虚函数调用。

null关键字 null 表示空指针;从技术上说,它的类型是 (void *) 。它可以被隐式地转换为任何指针类型。整数 0 不能被转换为空指针。null 也用于空数组。

true, false它们都是 bit 型的,值分别为 1 和 0 。

字符文字量字符文字量是单个的字符,类型是 char、 wchar 或者 dchar 。如果文字量是 \u 转义序列,类型就是 wchar 。如果文字量是 \U 转义序列,类型就是 dchar 。否则,它的类型是能够容纳它的最小的类型。

函数文字量函数文字量

function 函数体

function ( 参数列表 ) 函数体

function 类型 ( 参数列表 ) 函数体

delegate 函数体

delegate ( 参数列表 ) 函数体

delegate 类型 ( 参数列表 ) 函数体

FunctionLiteral

function FunctionBody

function ( ParameterList ) FunctionBody

function Type ( ParameterList ) FunctionBody

delegate FunctionBody

delegate ( ParameterList ) FunctionBody

delegate Type ( ParameterList ) FunctionBody

有了 函数文字量 ,就可以直接将匿名函数和匿名委托嵌入到表达式中。类型 是函数或委托的返回类型,如果忽略的话,会被认为是 void 。( 参数列表 ) 是传递给函数的参数。如果忽略的话,会被认为是空参数列表 () 。函数文字量的类型是指向函数或者委托的指针。

例如: int function(char c) fp;// 声明函数指针

void test()

{

static int foo(char c) { return 6; }

fp = &foo;

}

精确地等价于:int function(char c) fp;

void test()

{

fp = function int(char c) { return 6;} ;

}

而:int abc(int delegate(long i));

void test()

{ int b = 3;

int foo(long c) { return 6 + b; }

abc(&foo);

}

精确地等价于:int abc(int delegate(long i));

void test()

{ int b = 3;

abc( delegate int(long c) { return 6 + b; } );

}

匿名委托的行为就像任意的语句文字量。例如,下面的 loop 可以执行任何语句: double test()

{ double d = 7.6;

float f = 2.3;

void loop(int k, int j, void delegate() statement)

{

for (int i = k; i < j; i++)

{

statement();

}

}

loop(5, 100, delegate { d += 1; } );

loop(3, 10, delegate { f += 1; } );

return d + f;

}

与 嵌套函数 相比,function 形式类似于静态或者非嵌套函数,而 delegate 形式类似于非静态嵌套函数。换句话说,委托文字量可以访问它外围函数的堆栈,而函数文字量则不能。

断言表达式断言表达式:

assert ( 表达式 )

AssertExpression:

assert ( Expression )

断言会计算 表达式 。如果结果为假,会抛出一个 AssertError 异常。如果结果为真,不会抛出任何异常。如果 表达式 包含程序所依赖的任何副作用,就是一个错误。通过编译时的命令行选项,编译器可以根本不对断言表达式求值。断言表达式的结果的类型是 void 。断言是 D 支持 契约式编程 的一个基础。

Typeid 表达式Typeid表达式:

typeid ( 类型 )

TypeidExpression:

typeid ( Type )

返回同 类型 对应的 TypeInfo 类的实例。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有