インスタンスメソッドとself
コロン構文と暗黙のselfパラメーターを使ってメソッドを定義します。
「インスタンスメソッドとself」はCoddyKit上の無料Lua Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはLua Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Lua Academyコースには全4レッスンが含まれています。
selfはインスタンスです
obj:method()を呼び出すと、Luaはobjを最初の引数として自動的に渡します。このパラメーターは、慣例としてselfと名付けます。selfを通じて、メソッドはインスタンスデータにアクセスし、ほかのメソッドを呼び出します。
local Counter = {}
Counter.__index = Counter
function Counter.new(start)
return setmetatable({value=start or 0, step=1}, Counter)
end
function Counter:increment()
self.value = self.value + self.step
end
function Counter:getValue() return self.value end
local c = Counter.new(10)
c:increment(); c:increment()
print(c:getValue()) -- 12メソッドチェーン
メソッドからselfを返すと、チェーンを利用できます:obj:method1():method2():method3()。各呼び出しが同じオブジェクトを返すため、流れるような記述が可能になります。状態を変更するメソッドに最適です。
local Builder = {}
Builder.__index = Builder
function Builder.new()
return setmetatable({parts={}},Builder)
end
function Builder:add(s) self.parts[#self.parts+1]=s; return self end
function Builder:addAll(t)
for _,v in ipairs(t) do self.parts[#self.parts+1]=v end
return self
end
function Builder:build() return table.concat(self.parts," ") end
local result = Builder.new()
:add("Hello")
:add("from")
:addAll({"Lua","OOP"})
:build()
print(result) -- Hello from Lua OOPほかのメソッドの呼び出し
メソッドはself:otherMethod()を使って、同じインスタンス上のほかのメソッドを呼び出せます。これにより、クラス内でコードを再利用しやすくなります。プライベートなヘルパーは、selfを明示的に受け取る通常のlocal関数として定義できます。
local Stack = {}
Stack.__index = Stack
function Stack.new() return setmetatable({_data={},_size=0},Stack) end
function Stack:push(v) self._size=self._size+1; self._data[self._size]=v end
function Stack:pop()
if self:isEmpty() then return nil end
local v=self._data[self._size]; self._data[self._size]=nil
self._size=self._size-1; return v
end
function Stack:peek()
return not self:isEmpty() and self._data[self._size] or nil
end
function Stack:isEmpty() return self._size==0 end
function Stack:size() return self._size end
local s=Stack.new(); s:push(1);s:push(2);s:push(3)
print(s:pop(),s:peek(),s:size()) -- 3 2 2メソッドの上書きに関する警告
クラスメソッドと同じ名前のインスタンスフィールドを設定すると、そのインスタンスではメソッドが隠蔽されます。通常はバグなので、インスタンスフィールド名がメソッド名と衝突する可能性がある場合は注意してください。
local Dog = {}
Dog.__index = Dog
function Dog.new(n) return setmetatable({name=n},Dog) end
function Dog:speak() print(self.name..": Woof!") end
local d = Dog.new("Rex")
d:speak() -- Rex: Woof!
-- Accidental shadow:
d.speak = "loud" -- now d.speak is a string, not a function
local ok,err = pcall(function() d:speak() end)
print(ok, err) -- false attempt to call a string valueコールバック内のself
メソッドをコールバックとして渡すと、暗黙的なselfが失われます。クロージャーでメソッドをラップし、selfを捕捉してください。
local Timer = {}
Timer.__index = Timer
function Timer.new(n) return setmetatable({count=n},Timer) end
function Timer:tick()
self.count=self.count-1
print("Ticking, count:", self.count)
end
local t = Timer.new(3)
-- Wrong: loses self
-- local cb = t.tick -- cb(t) works but cb() doesn't
-- Correct: closure captures self
local cb = function() t:tick() end
cb(); cb(); cb() -- Ticking 3 times静的メソッドとインスタンスメソッド
静的メソッドはインスタンスではなくクラスに対して呼び出します。selfを持たないか、クラスをselfとして受け取ります。Luaには正式な区別がないため、静的メソッドには慣例として.(:ではなく)を使用します。
local MathUtils = {}
MathUtils.__index = MathUtils
-- Static method (no instance needed)
function MathUtils.clamp(v, lo, hi)
return math.max(lo, math.min(hi, v))
end
-- Instance method (needs self)
function MathUtils:scale(factor)
self.value = self.value * factor
end
print(MathUtils.clamp(15, 0, 10)) -- 10
local m = setmetatable({value=5},MathUtils)
m:scale(3)
print(m.value) -- 15Mixinメソッド
正式な継承を使わずに、mixinテーブルのメソッドをクラスに追加します。これはフラットなコンポジションであり、mixinの関数をクラスのテーブルにコピーするか参照させます。
local Serializable = {}
function Serializable:serialize()
local parts={}
for k,v in pairs(self) do
if type(v)~="function" then
parts[#parts+1]=k.."="..tostring(v)
end
end
return "{"..table.concat(parts,",").."}"
end
local User = {}
User.__index = User
User.serialize = Serializable.serialize -- mixin!
function User.new(n,a) return setmetatable({name=n,age=a},User) end
local u = User.new("Alice",30)
print(u:serialize())抽象メソッド
Luaは抽象メソッドを強制しませんが、エラーを発生させる基底クラスのメソッドを定義し、サブクラスに上書きを要求できます。これは「必ず上書きする」という慣例です。
local Shape = {}
Shape.__index = Shape
function Shape.new() return setmetatable({},Shape) end
function Shape:area()
error(type(self).." must implement area()",2)
end
function Shape:describe()
print("Shape area:", self:area())
end
local sq={}
setmetatable(sq,{__index=Shape})
function sq:area() return 4*4 end
sq:describe() -- Shape area: 16メソッドテーブル
メソッドが多いクラスでは、機能ごとにグループ化して整理します。同じテーブル内のすべてのメソッドは同じメタテーブル検索を共有しますが、サブ名前空間を使って関心事ごとに分割できます。
local Entity = {}
Entity.__index = Entity
Entity.Physics = {}
function Entity.Physics:applyForce(fx,fy)
self.vx=(self.vx or 0)+fx
self.vy=(self.vy or 0)+fy
end
Entity.Render = {}
function Entity.Render:draw()
print(string.format("Draw at (%g,%g)",self.x or 0,self.y or 0))
end
-- Mix into main class
for k,v in pairs(Entity.Physics) do Entity[k]=v end
for k,v in pairs(Entity.Render) do Entity[k]=v end
function Entity.new(x,y) return setmetatable({x=x,y=y},Entity) end
local e=Entity.new(10,20); e:draw(); e:applyForce(5,0); print(e.vx)委譲と継承
深い継承チェーンよりも、参照を保持する委譲を優先してください。クラスは別のオブジェクトから継承する代わりに処理を委譲できるため、結合度を低く保ち、各クラスの責務を明確にできます。
local Logger = {}
Logger.__index = Logger
function Logger.new(name) return setmetatable({name=name},Logger) end
function Logger:log(msg) print("["..self.name.."] "..msg) end
local Service = {}
Service.__index = Service
function Service.new(name)
return setmetatable({
name=name,
logger=Logger.new(name) -- delegation
},Service)
end
function Service:start()
self.logger:log("starting...") -- delegate logging
print(self.name, "running")
end
Service.new("AuthService"):start()クイックチェック
obj:method()とobj.method()の違いは何ですか?
復習:インスタンスメソッド
まとめ:
- コロン呼び出し構文:
obj:method()==obj.method(obj) - メソッドチェーンのためにselfを返す
- ほかのメソッドを呼び出す:
self:otherMethod() - コールバックでは、selfを保持するためにクロージャーでラップする
- 静的メソッドには慣例としてドット記法を使用する
- 柔軟性のため、深い継承より委譲を優先する
よくある質問
「インスタンスメソッドとself」レッスンは無料ですか?
はい。「インスタンスメソッドとself」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Lua Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Lua Academyコースには全4レッスンが含まれています。
「インスタンスメソッドとself」で何を学びますか?
コロン構文と暗黙のselfパラメーターを使ってメソッドを定義します。 ブラウザで直接実行するハンズオンコードでLua Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Lua Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのLua Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「インスタンスメソッドとself」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このLua Academyレッスンでコードを書いて実行できますか?
はい。すべてのLua Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- メタテーブルによるクラス
- コンストラクターとnew()
- インスタンスメソッドとself
- クロージャによるカプセル化