上一章:列舉 目錄 下一章:延伸方法


值型別

編輯

在 CLI 程式裏,正如前面所討論的,有兩種類型的值。在數值運算式裏,值會被複製,而不是參考。對數值來說,複製是個廉價的動作,因為只需要複製幾個 bytes。通常你不會想要在物件上做相同的動作,不過有時候的確有必要在某些型別這樣作,這時候就可以考慮將該型別定義為 struct。

struct Point3D:
	public X as double
	public Y as double
	public Z as double
	
	def constructor(x as double, y as double, z as double):
		X = x;  Y = y;   Z = z
		
	def Add(p as Point3D):
		return Point3D(X + p.X, Y + p.Y, Z + p.Z)
		
	override def ToString():
		return "(${X},${Y},${Z})"

p1 = Point3D(10.0,20.0,30.0)
p2 = Point3D(1.0,1.0,2.0)
print p1,p2,p1.Add(p2)

執行結果

(10,20,30) (1,1,2) (11,21,32)

運算子的覆載

編輯

或許你會想改變 x+y 的動作。舉例來說,前面提到的Point3D可以用來表現 3D 空間的向量,然後可以加上向量。加的動作應該是以數學的 + 來進行,這樣更直覺 (所以也可以用在複數或矩陣上)。要為 3D 向量覆載+的話,以下列的靜態方法取代原來的 Add 方法即可:

	static def op_Addition(self as Point3D, p as Point3D):
		return Point3D(self.X + p.X, self.Y + p.Y, self.Z + p.Z)

這兒有兩件事情要提醒,必須是靜態方法,而且要使用運算子的內部名稱。

當你進行覆載時,最好也針對所有相關的數值運算作覆載。如果你覆載了"加",你必須也覆載"減"與一元運算的"減"﹔如果你覆載了"乘",你必須也覆載"除"。

這些是你可以覆載的運算名稱(此處以 Boo 0.7.5 為準):

  • op_Addition +
  • op_Subtraction -
  • op_Multiply *
  • op_Division /
  • op_Modulus %
  • op_Exponentiation **
  • op_Equality ==
  • op_LessThan <
  • op_LessThanOrEqual <=
  • op_GreaterThan >
  • op_GreaterThanOrEqual >=
  • op_Match =~
  • op_NotMatch not =~
  • op_Member in
  • op_NotMember not in
  • op_BitwiseOr |
  • op_BitwiseAnd &
  • op_UnaryNegation -

因為 x+=y 相等於 x=x+y,覆載 + 會自動覆載 +=。But,OverloadInPlaceAddition(譯註:難以翻譯,保留原文)。

如果你無法肯定是否要覆載的話,就不要覆載。這是很危險的,因為你正在發明新的表示方法,而這可能會使其他人困擾,並使你的程式難以理解。舉例來說吧,add 並不一定是加,像加入一個 customer 到 customer 串列時,就不應該去覆載+,因為這樣的動作並沒有產生新串列,不應該讓 + 有不同的語意(譯註:因為覆載以後,通常需要傳回新物件,看看上面的例子。)。

OverloadInPlaceAddition
編輯

It would probably be useful to allow binary operations like InPlaceAddition to be overloaded directly, because just relying on the usual x += y ==> x = x + y leads to potentially inefficient code for value types.

The question is, why restrict overloading at all?


上一章:列舉 目錄 下一章:延伸方法