この初版はLua 5.0向けに書かれました。後続バージョンでも大部分は関連性がありますが、いくつかの違いがあります。
第4版はLua 5.3を対象としており、Amazonおよびその他の書店で入手可能です。
本書を購入することで、Luaプロジェクトの支援にも貢献できます。
![]() |
プログラミング inLua | ![]() |
第II部. テーブルとオブジェクト 第16章. オブジェクト指向プログラミング |
クラスは、オブジェクト作成のための鋳型として機能します。多くのオブジェクト指向言語はクラスの概念を提供します。そのような言語では、各オブジェクトは特定のクラスのインスタンスです。Luaにはクラスの概念がありません。各オブジェクトは独自の動作を定義し、独自の形状を持っています。しかしながら、SelfやNewtonScriptなどのプロトタイプベースの言語を参考にすれば、Luaでクラスをエミュレートするのは困難ではありません。これらの言語では、オブジェクトはクラスを持ちません。代わりに、各オブジェクトはプロトタイプを持つ場合があります。プロトタイプは通常のオブジェクトであり、最初のオブジェクトは自分が知らない操作をそこで検索します。そのような言語でクラスを表すには、他のオブジェクト(そのインスタンス)のプロトタイプとして排他的に使用されるオブジェクトを作成するだけです。クラスとプロトタイプはどちらも、複数のオブジェクトで共有される動作を配置する場所として機能します。
Luaでは、前の章で見た継承のアイデアを使用して、プロトタイプを実装するのは簡単です。より具体的に言うと、2つのオブジェクトa
とb
がある場合、b
をa
のプロトタイプにするために必要なのは
setmetatable(a, {__index = b})これ以降、
a
は自分が持っていない操作をb
で検索します。b
をオブジェクトa
のクラスと見なすのは、用語の変更以上のことはありません。銀行口座の例に戻りましょう。Account
と同様の動作を持つ他の口座を作成するには、これらの新しいオブジェクトが__index
メタメソッドを使用してAccount
から操作を継承するように配置します。口座オブジェクトのメタテーブルとして追加のテーブルを作成する必要がないという小さな最適化に注意してください。その目的のためにAccount
テーブル自体を使用できます。
function Account:new (o) o = o or {} -- create object if user does not provide one setmetatable(o, self) self.__index = self return o end(
Account:new
を呼び出すとき、self
はAccount
と等しくなります。そのため、self
の代わりにAccount
を直接使用することもできました。ただし、次のセクションでクラス継承を紹介する際に、self
の使用が適切に適合します。)そのコードの後、新しい口座を作成してそのメソッドを呼び出すと何が起こるでしょうか?a = Account:new{balance = 0} a:deposit(100.00)この新しい口座を作成すると、
a
はメタテーブルとしてAccount
(Account:new
呼び出しでのself)を持ちます。その後、a:deposit(100.00)
を呼び出すと、実際にはa.deposit(a, 100.00)
を呼び出しています(コロンは構文上の砂糖にすぎません)。しかし、Luaはテーブルa
に"deposit"
エントリを見つけることができません。そのため、メタテーブルの__index
エントリを調べます。状況はほぼ次のようになります。getmetatable(a).__index.deposit(a, 100.00)
a
のメタテーブルはAccount
であり、Account.__index
もAccount
です(新しいメソッドがself.__index = self
を実行したため)。したがって、前の式を次のように書き直すことができます。Account.deposit(a, 100.00)つまり、Luaは元の
deposit
関数を呼び出しますが、selfパラメーターとしてa
を渡します。そのため、新しい口座a
はAccount
からdeposit
関数を継承しました。同じメカニズムによって、Account
からすべてのフィールドを継承できます。継承はメソッドだけでなく、新しい口座にない他のフィールドにも機能します。したがって、クラスはメソッドだけでなく、インスタンスフィールドのデフォルト値も提供します。最初のAccount
の定義では、値0のbalance
フィールドを提供したことを思い出してください。したがって、初期残高なしで新しい口座を作成すると、このデフォルト値を継承します。
b = Account:new() print(b.balance) --> 0
b
でdeposit
メソッドを呼び出すと、次のものと同等の処理が実行されます。b.balance = b.balance + v(
self
はb
であるため)。式b.balance
は0と評価され、初期預金がb.balance
に割り当てられます。次にこの値を要求すると、インデックスメタメソッドは呼び出されません(b
が独自のbalance
フィールドを持つようになったため)。Copyright © 2003–2004 Roberto Ierusalimschy. All rights reserved. | ![]() |