D語言中的表達式(二)

 

In 表達式

	關係表達式 in 移位表達式
	RelExpression in ShiftExpression
	
可以檢測一個元素是否在關聯數組中:
	 foo[[]];
	……
	 ("hello"  foo)
		……
	
in 表達式同關係表達式 <、<= 等有相同的優先級。

移位表達式

	移位表達式 << 和表達式
	移位表達式 >> 和表達式
	移位表達式 >>> 和表達式
	ShiftExpression << AddExpression
	ShiftExpression >> AddExpression
	ShiftExpression >>> AddExpression
	
操作數必須是整數類型,並且會使用常用的整數提升。結果的類型是左操作數提升後的類型。結果的值是左操作數移動右操作數指定的位得到的值。

<< 是左移,>> 是有符號右移(譯註:也叫算術右移)。>>> 是無符號右移。(譯註:也叫邏輯右移)

如果要移動的位數超過了左操作數的位數,會被認爲是非法的:

	 c;
	c << 33;	error
	

和表達式

	和表達式 + 積表達式
	和表達式 - 積表達式
	和表達式 ~ 積表達式
	AddExpression + MulExpression
	AddExpression - MulExpression
	AddExpression ~ MulExpression
	
如果操作數是整數類型,會應用整數提升,然後會通過常用的算術轉換提升爲它們的公共類型。

如果有操作數爲浮點類型,另一個操作數會被隱式地轉換爲浮點類型,然後會通過常用的算術轉換提升爲它們的公共類型。

如果運算符是 +- ,第一個操作數是指針,並且第二個操作數是整數類型,結果的類型就是第一個操作數的類型,結果的值是指針加上(或減去)第二個操作數乘以指針所指類型的大小得到的值。

如果指針所指的類型是 bit ,結果的值是第二個操作數除以 8 後與指針相加得到的指。如果第二個操作數不能被 8 整除,會被視爲非法。

	* p;
	p += 1;		
	p += 8;		
	
如果第二個操作數是指針,第一個操作數是整數類型,並且運算符是 + ,會按照上面所說的方式進行指針運算,只不過操作數的順序反過來。

浮點操作數的和表達式不是可結合的。

積表達式

	積表達式 * 一元表達式
	積表達式 / 一元表達式
	積表達式 % 一元表達式
	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 表達式用來在垃圾收集堆(默認情況)上或使用類指定的分配器分配內存。

在爲多維數組分配內存時,聲明按照同讀取後綴數組聲明順序相同的順序讀取聲明。

	[][] foo;		
	...
	foo = [][30];	
	

轉型表達式

在 C 和 C++ 中,類型轉換的形式爲:
	(類型) 一元表達式
	(type) unaryexpression
	
但是,這會在語法上造成歧義。考慮:
		(foo) - p;
	
這是將負 p 轉型爲 foo ,還是 foo 減去 p ?如果不通過查找符號表以確定它究竟是一個類型還是一個變量,就不可能作出判斷。但 D 的設計目標就是使語法爲上下文無關的——應該無需檢索符號表就能進行語法分析。所以,爲了區分轉型和帶括號的字表達式,需要引入不同的語法。

C++ 通過引入:

	dynamic_cast<類型>(表達式)
	dynamic_cast<type>(expression)
	
解決這個問題,但這寫起來又醜陋又笨拙。D 引入了 cast 關鍵字:
	cast(foo) -p;	
	(foo) - p;	
	
cast 具有很好的性質,可以很容易地通過文本查找方式找到它,還會減輕那些被無情地重載的‘()’運算符的負擔。

在轉型的其他方面,D 同 C/C++ 也有所不同。任何從類引用到派生類引用的轉換都會執行運行時檢查以確保轉型是適當的。這種行爲等價於 C++ 中的 dynamic_cast 運算符。

	 A { ... }
	 B : A { ... }

	 test(A a, B b)
	{
	     B bx = a;		
	     B bx = (B) a;	
	     A ax = b;		
	     A ax = (A) b;	
	}
	
如果想要檢測一個對象 o 是否是類 B 的一個實例,可以使用轉型:
	 (cast(B) o)
	{
	    
	}
	
	{
	   
	}
	

後綴表達式

	後綴表達式 . 標誌符
	後綴表達式 -> 標誌符
	後綴表達式 ++
	後綴表達式 --
	後綴表達式 ( 參數列表 )
	後綴表達式 [ 參數列表 ]
	後綴表達式 [ 賦值表達式 .. 賦值表達式 ]
	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) 調用的,會生成一個非虛函數調用:
	 A
	{
	     get() {  ; }

	     foo() {  typeof(this).get(); }
	     bar() {  this.get(); }
	}

	 B : A
	{
	     get() {  ; }
	}

	 main()
	{
	    B b =  B();

	    b.foo();		
	    b.bar();		
	}
	

super

在非靜態成員函數內,super 是指向調用此函數的對象的指針,而這個指針被轉換爲它的基類類型的指針。如果不存在相應的基類,就會被認爲是錯誤。super 不允許出現在結構的成員函數中。如果成員函數是顯式地通過引用 super 調用的,會生成一個非虛函數調用。

null

關鍵字 null 表示空指針;從技術上說,它的類型是 (void *) 。它可以被隱式地轉換爲任何指針類型。整數 0 不能被轉換爲空指針。null 也用於空數組。

true, false

它們都是 bit 型的,值分別爲 1 和 0 。

字符文字量

字符文字量是單個的字符,類型是 charwchar 或者 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( 參數列表 ) 是傳遞給函數的參數。如果忽略的話,會被認爲是空參數列表 () 。函數文字量的類型是指向函數或者委託的指針。

例如:

	 ( c) fp;	
	 test()
	{
	      foo( c) {  6; }

	    fp = &foo;
	}
	
精確地等價於:
	( c) fp;

	 test()
	{
	    fp = function int(char c) { return 6;} ;
	}
	
而:
	 abc((long i));

	 test()
	{    b = 3;
	     foo( c) {  6 + b; }

	    abc(&foo);
	}
	
精確地等價於:
	 abc(( i));

	 test()
	{   b = 3;

	    abc( delegate int(long c) { return 6 + b; } );
	}
	
匿名委託的行爲就像任意的語句文字量。例如,下面的 loop 可以執行任何語句:
	 test()
	{    d = 7.6;
	     f = 2.3;

	     loop( k,  j,  () statement)
	    {
		for ( i = k; i < j; i++)
		{
		    statement();
		}
	    }

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

	     d + f;
	}
	
與 嵌套函數 相比,function 形式類似於靜態或者非嵌套函數,而 delegate 形式類似於非靜態嵌套函數。換句話說,委託文字量可以訪問它外圍函數的堆棧,而函數文字量則不能。

斷言表達式

	斷言表達式:
		assert ( 表達式 )
	AssertExpression:
		assert ( Expression )
	
斷言會計算 表達式 。如果結果爲假,會拋出一個 AssertError 異常。如果結果爲真,不會拋出任何異常。如果 表達式 包含程序所依賴的任何副作用,就是一個錯誤。通過編譯時的命令行選項,編譯器可以根本不對斷言表達式求值。斷言表達式的結果的類型是 void 。斷言是 D 支持 契約式編程 的一個基礎。

Typeid 表達式

	Typeid表達式:
	    typeid ( 類型 )	
	TypeidExpression:
	    typeid ( Type )
	
返回同 類型 對應的 TypeInfo 類的實例。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章