下記の様なレコード型 TBar があります。
■ リスト1
TBar = recordFBaz: Boolean;constructor Create(const iBaz: Boolean);procedure SetBaz(const iBaz: Boolean);end;// レコード型のコンストラクタは引数がないといけないconstructor TBar.Create(const iBaz: Boolean);beginSetBaz(iBaz);end;// FBaz を設定する Accesserprocedure TBar.SetBaz(const iBaz: Boolean);beginFBaz := iBaz;end;
TBar をリストに持つ TFoo があります。
■ リスト2
TFoo = classFBars: TList<TBar>;procedure Check;constructor Create; reintroduce;destructor Destroy; override;end;constructor TFoo.Create;varBar: TBar;begininherited;// リストを生成FBars := TList<TBar>.Create;// FBaz = False で生成FBars.Add(TBar.Create(False));// FBaz = True に設定for Bar in FBars doBar.SetBaz(True);end;destructor TFoo.Destroy;beginFBars.Free;inherited;end;
では、このとき、下記のコードを実行すると何が出力されるでしょうか?
■ リスト3
beginwith TFoo.Create dotryif (FBars[0].FBaz) thenWriteln('TRUE')elseWriteln('FALSE');Readln;finallyFree;end;end.
こんな風に書いているから丸わかりでしょうが、答えは FALSE です。
何故かと言うとレコードはあくまでレコードだから、です。
クラスのようにメソッドを持てるようになりましたが、(当然ですが)レコード型の代入は値のコピーが渡されるに過ぎません。
クラスなら、変数に保持されているのはポインタですので、値を変更すれば元の値が変わります
なので「リスト2」にあった下記のコードは
varBar: TBar;begin(略)// ローカル変数 Bar の FBaz が設定されただけで// FBars[0] の Bar が設定されるわけではない!for Bar in FBars doBar.SetBaz(True);end;
あくまでローカル変数に対しての操作になります。
ローカル変数ですのでメソッドを抜けたら、破棄されます。
クラス感覚で、レコード型を使うと痛い目にあうよ!というお話しでした。
つまり痛い目に遭ったわけです……
TStyleProvider が更新されております……
ちなみに、SetBaz というメソッドを作ったのは、下記の様に代入エラーが出るからです。
これで気づきました。
for Bar in FBars doBar.FBaz := True; // 代入できない左辺値エラー
0 件のコメント:
コメントを投稿