上一章:列举 目录 下一章:延伸方法


值型别

编辑

在 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?


上一章:列举 目录 下一章:延伸方法