使用 Delphi XE4 (update1)和 FMX ,我希望移动相机使用此代码(在wheel-mouse事件中):
AVector := Vector3D(0, 0, 3);
Camera.Position.Vector.AddVector3D(AVector);
代码编译,什么都不做。使用de调试器时,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;
我的代码有什么问题???
答案 0 :(得分:4)
Camera.Position
的类型为TPosition3D
。 TPosition3D.Vector
是TVector3D
类型的属性,带有getter和setter。请注意,TVector3D
是一个记录,它是值类型而不是引用类型。这个细节至关重要。
所以,当你写Camera.Position.Vector
时,你指的是矢量的副本。它是一个副本,因为TVector3D
是值类型。
因此,非工作代码相当于:
var
TempVec: TVector3D;
....
TempVec := Camera.Position.Vector;
TempVec.AddVector3D(...);
显然,对AddVector3D
的调用不会修改Camera.Position
,因为对AddVector3D
的调用只会改变临时本地。
在您的代码中,该临时局部变量仍然存在,但您没有给它命名。这是一个隐藏的隐含变量。
为了修改位置,您必须对Vector
属性进行赋值,这正是工作代码所做的。
作为一般规则,支持就地变异的价值类型通常表示设计不佳。因此,在我看来,Embarcadero工程师绝不应该添加变异实例方法,如AddVector3D
,Normalize
,Scale
等。这些方法导致了这种混乱。相反,使用返回新值的函数可以更好地实现该功能,就像重载运算符一样。