0Pricing
Lua Academy · レッスン

__indexチェーンによる単一継承

親クラスをメタテーブルの__indexに設定してメソッドを継承します。

「__indexチェーンによる単一継承」はCoddyKit上の無料Lua Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはLua Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Lua Academyコースには全4レッスンが含まれています。

プロトタイプチェーン

単一継承は、子クラスの__indexを親クラスに設定することで機能します。子クラスでメソッドが見つからない場合、Luaは親クラスを検索します。これによりプロトタイプチェーンが形成されます。

local Base={}
Base.__index=Base
function Base.new() return setmetatable({},Base) end
function Base:greet() print("Hello from Base") end

local Child={}
Child.__index=Child
setmetatable(Child,{__index=Base})  -- Child inherits Base

function Child.new() return setmetatable({},Child) end

local c=Child.new()
c:greet()  -- Hello from Base (inherited)

メソッド解決順序

インスタンスでメソッドを呼び出すときは、(1)インスタンステーブル、(2)Child(__index経由)、(3)Base(Childのメタテーブルの__index経由)の順に検索します。最初に見つかったものが使用されます。

local Base={}
Base.__index=Base
function Base:who() print("I am Base") end

local Child={}
Child.__index=Child
setmetatable(Child,{__index=Base})
function Child:who() print("I am Child") end  -- override

local b=setmetatable({},Base)
local c=setmetatable({},Child)
b:who()  -- I am Base
c:who()  -- I am Child (overrides)

コンストラクターの継承

子クラスは親クラスのコンストラクターを呼び出して再利用することも、親の初期化を拡張する独自のコンストラクターを定義することもできます。

local Animal={}
Animal.__index=Animal
function Animal.new(name,sound)
  return setmetatable({name=name,sound=sound},Animal)
end
function Animal:speak() print(self.name..": "..self.sound) end

local Dog={}
Dog.__index=Dog
setmetatable(Dog,{__index=Animal})

function Dog.new(name)
  local self = Animal.new(name,"Woof")
  return setmetatable(self,Dog)
end
function Dog:fetch(item) print(self.name.." fetches "..item) end

local d=Dog.new("Rex")
d:speak(); d:fetch("ball")

祖先の確認

メタテーブルチェーンを上にたどることで、オブジェクトのクラスが指定された基底クラスを継承しているか確認できます。これがLuaにおけるinstanceofの仕組みです。

local function instanceof(obj, cls)
  local mt = getmetatable(obj)
  while mt do
    if mt == cls then return true end
    mt = getmetatable(mt)
  end
  return false
end

スーパー呼び出し

上書きしたメソッドの親クラス版を呼び出すには、親クラスのテーブルから直接アクセスします。

local Base={}
Base.__index=Base
function Base:init(x) self.x=x end
function Base:value() return self.x end

local Child={}
Child.__index=Child
setmetatable(Child,{__index=Base})
function Child:init(x,y)
  Base.init(self,x)  -- call parent
  self.y=y
end
function Child:value() return Base.value(self)+self.y end

local c=setmetatable({},Child)
c:init(3,4)
print(c:value())  -- 7

深いチェーン

A → B → Cという3段階の階層を構築します。メソッド検索は、見つかるまでチェーン全体をたどります。

local A={}
A.__index=A
function A:aMethod() print("A method") end

local B={}
B.__index=B
setmetatable(B,{__index=A})
function B:bMethod() print("B method") end

local C={}
C.__index=C
setmetatable(C,{__index=B})

local c=setmetatable({},C)
c:bMethod()  -- from B
c:aMethod()  -- from A

フィールドの上書き

インスタンスに直接設定することで、クラスレベルのフィールドを上書きできます。クラスのフィールド自体は変更されず、そのインスタンス上で隠蔽されるだけです。

local Creature={}
Creature.__index=Creature
Creature.hp=100
Creature.speed=10

function Creature.new()
  return setmetatable({},Creature)
end

local fast=Creature.new()
fast.speed=20  -- override for this instance

local normal=Creature.new()

print(fast.speed,normal.speed,Creature.speed)  -- 20  10  10

クラスレベルの継承

setmetatable(Child, {__index=Parent})を設定すると、クラスレベルの検索が親クラスへフォールバックするようになります。これにより、Child.classMethod()は上書きされていなければ親クラスのメソッドを見つけます。

local Vehicle={}
Vehicle.__index=Vehicle
Vehicle.maxSpeed=120
function Vehicle.describe() print("Vehicle") end

local Car={}
Car.__index=Car
setmetatable(Car,{__index=Vehicle})

Car.describe()  -- Vehicle (inherited class method)
print(Car.maxSpeed)  -- 120 (inherited class field)

初期化チェーン

正しく初期化するには、子コンストラクターが親コンストラクターを呼び出し、親の状態が設定されるようにします。階層を上に向かって初期化を連鎖させてください。

local Base={}
Base.__index=Base
function Base:_init(name) self.name=name end

local Mid={}
Mid.__index=Mid
setmetatable(Mid,{__index=Base})
function Mid:_init(name,level)
  Base._init(self,name)
  self.level=level
end

local Top={}
Top.__index=Top
setmetatable(Top,{__index=Mid})
function Top.new(name,level,role)
  local self=setmetatable({},Top)
  Mid._init(self,name,level)
  self.role=role
  return self
end

local t=Top.new("Alice",5,"admin")
print(t.name,t.level,t.role)

抽象基底クラス

未実装のメソッドでエラーを発生させる基底クラスを作成します。サブクラスはこれらのメソッドを上書きする必要があります。これにより、Luaの動的型システムでインターフェースの契約を強制できます。

local Serializer={}
Serializer.__index=Serializer
function Serializer:encode(data)
  error(self._type.." must implement encode()",2)
end
function Serializer:decode(str)
  error(self._type.." must implement decode()",2)
end

local JSONSerializer={_type="JSON"}
setmetatable(JSONSerializer,{__index=Serializer})
function JSONSerializer:encode(data)
  return "{"..tostring(data.key).."}"
end

local j=setmetatable({_type="JSON"},JSONSerializer)
print(j:encode({key="val"}))

継承に関する質問

Luaで単一継承を可能にするものは何ですか?

復習:単一継承

setmetatable(Child, {__index = Parent})を設定してメソッドを継承します。__indexチェーンによって自動的な委譲が行われます。Childでメソッドを定義すれば上書きでき、Parent.method(self)で親を明示的に呼び出せます。

よくある質問

「__indexチェーンによる単一継承」レッスンは無料ですか?

はい。「__indexチェーンによる単一継承」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Lua Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Lua Academyコースには全4レッスンが含まれています。

「__indexチェーンによる単一継承」で何を学びますか?

親クラスをメタテーブルの__indexに設定してメソッドを継承します。 ブラウザで直接実行するハンズオンコードでLua Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Lua Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのLua Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「__indexチェーンによる単一継承」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このLua Academyレッスンでコードを書いて実行できますか?

はい。すべてのLua Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. __indexチェーンによる単一継承
  2. superによる親メソッドの呼び出し
  3. Mixinパターン
  4. オーバーライドとポリモーフィズム
← Lua Academyに戻る