2

使用Delphi XE4 (update1) 和FMX,我想用这段代码移动相机(在滚轮鼠标事件中):

AVector := Vector3D(0, 0, 3);
Camera.Position.Vector.AddVector3D(AVector);

代码编译,什么都不做。使用调试器,Camera.Position.Vector不会改变

当用

AVector := Vector3D(0, 0, 3);
Camera.Position.Vector := Camera.Position.Vector + AVector;

...有用 !!!足够奇怪,因为该AddVector3D()函数正是执行此代码!

procedure TVector3D.AddVector3D(const AVector3D: TVector3D);
begin
  Self := Self + AVector3D;
end;

我的代码有什么问题???

4

1 回答 1

4

Camera.Position是类型TPosition3D。并且TPosition3D.VectorTVector3D具有 getter 和 setter 的类型属性。请注意,这TVector3D是一条记录,它是值类型而不是引用类型。这个细节至关重要。

因此,当您编写时,Camera.Position.Vector您指的是向量的副本。它是一个副本,因为它TVector3D是一种值类型。

因此,非工作代码相当于:

var
  TempVec: TVector3D;
....
TempVec := Camera.Position.Vector;
TempVec.AddVector3D(...);

显然,调用AddVector3D不会修改Camera.Position,因为调用AddVector3D只会改变临时本地。

在您的代码中,该临时局部变量仍然存在,但您没有给它命名。这是一个隐藏的隐式变量。

为了修改位置,您必须对Vector属性进行赋值,这正是工作代码所做的。

作为一般规则,支持就地突变的值类型通常表示设计不佳。所以,在我看来,Embarcadero 工程师不应该添加变异实例方法,如,AddVector3D等等。这种方法会导致这种混乱。相反,使用返回新值的函数可以更好地实现该功能,就像重载运算符一样。NormalizeScale

于 2013-07-24T20:31:34.450 回答