モジュールスクリプトでは、「:」を使う場合と「.」を使う場合があります。私自身、間違った認識をしていた時期がありましたので、このページで詳しくまとめてみたいと思います。
簡単に説明すると、「:」 は メソッド呼び出し に使われ、「.」 は 通常の関数呼び出し に使われますが
もう少し詳しく解説しておきます。
1. メソッド(:)とは?
「:」 を使うと、関数が「そのオブジェクトに関連づけられたメソッド」として動作します。このとき、呼び出された関数の第1引数として、そのオブジェクト(self
)が自動的に渡されます。
具体例
local TestModule = {}
function TestModule:sayHello()
print("Hello, my name is " .. self.name)
end
return TestModule
上記のスクリプトでは、sayHello
関数は TestModule
オブジェクトに関連づけられたメソッドです。
使用例
local TestModule = require(script.TestModule)
TestModule.name = "Roblox"
TestModule:sayHello() -- 出力: Hello, my name is Roblox
ここで 「:」 を使うことで、TestModule
自身(self
)が関数の第1引数として渡されています。
2. 通常の関数(.)とは?
一方で、「.」 を使うと、関数が「ただの普通の関数」として動作します。この場合、オブジェクト(self
)は自動的に渡されません。
具体例
local TestModule = {}
function TestModule.sayHello()
print("Hello!")
end
return TestModule
上記では、sayHello
関数は TestModule
に関連づけられてはいますが、self
は使用されません。
使用例
local TestModule = require(script.TestModule)
TestModule.sayHello() -- 出力: Hello!
ここで .
を使うことで、オブジェクトに依存しない関数として呼び出されています。
「: 」と「 .」の主な違いを比較
ポイント | :(メソッド) | .(通常の関数) |
---|---|---|
動作の目的 | オブジェクトに依存する関数を呼び出す | 独立した関数を呼び出す |
self の扱い | 自動的に渡される | 渡されない |
使い方の例 | TestModule:sayHello() | TestModule.sayHello() |
コードの書き方 | function TestModule:sayHello() | function TestModule.sayHello() |
まとめ
- 「:」 は、関数がオブジェクトに依存して動作する場合(例えば、オブジェクトのプロパティを使いたい場合)に使います。このとき
self
が便利に扱えます。 - 「.」 は、オブジェクトに依存しない通常の関数を定義・呼び出す場合に使います。
例えば、オブジェクトの状態(プロパティ)を変更したり参照したい場合は、「:」 を使ったほうがよいでしょう。一方で、計算やユーティリティ関数のように、特定のオブジェクトに依存しない場合は「 .」 を使うのが適切です。
selfとは?
self
とは、Luaでメソッドを呼び出す際に使われる特別なキーワードです。これは、そのメソッドを呼び出した オブジェクト自身を表す参照 として使われます。言い換えれば、「そのメソッドが属するオブジェクトそのもの」を指します。
1. self が使われる場面
主に「 :」 を使ってメソッドを呼び出すときに self
が自動的に渡されます。
例:
local Object = {}
function Object:sayHello()
print("Hello, I am " .. self.name)
end
上記では、sayHello
は Object
の一部(メソッド)であり、self
は Object
自身を指します。
2. self を使う理由
普通の関数(.
で定義された関数)には、関数の中でその関数が属するオブジェクトへの自動的な参照はありません。一方、self
を使うことで、関数がどのオブジェクトに関連しているかを把握できるようになります。
比較例
通常の関数の場合(.
を使う)
local Object = {}
function Object.sayHello()
print("Hello, I am " .. Object.name)
end
Object.name = "Roblox"
Object.sayHello() -- 出力: Hello, I am Roblox
このコードは動きますが、関数の中で Object
を直接指定する必要があります。このようにハードコーディングすると、別のオブジェクトに対応する際に不便です。
メソッドの場合(: と self を使う)
local Object = {}
function Object:sayHello()
print("Hello, I am " .. self.name)
end
Object.name = "Roblox"
Object:sayHello() -- 出力: Hello, I am Roblox
この場合、self
は自動的に Object
を参照します。もし別のオブジェクトにメソッドを渡しても問題なく動作します。
local AnotherObject = { name = "Another" }
AnotherObject.sayHello = Object.sayHello
AnotherObject:sayHello() -- 出力: Hello, I am Another
3. self を用いた実用的な例
self
の便利さを理解するために、オブジェクト指向プログラミングの簡単な例を見てみましょう。
例: キャラクター管理システム
local Character = {}
function Character:new(name)
local newObj = { name = name, health = 100 }
setmetatable(newObj, self)
self.__index = self
return newObj
end
function Character:takeDamage(amount)
self.health = self.health - amount
print(self.name .. " took " .. amount .. " damage! Remaining health: " .. self.health)
end
return Character
使用例
local Character = require(script.Character)
local player1 = Character:new("Player1")
local player2 = Character:new("Player2")
player1:takeDamage(20) -- 出力: Player1 took 20 damage! Remaining health: 80
player2:takeDamage(30) -- 出力: Player2 took 30 damage! Remaining health: 70
このコードでは、self
によってどのキャラクターがダメージを受けているかを動的に追跡できます。
4. self を使用しないとどうなる?
もし self
を使わない場合、以下の問題が発生する可能性があります。
問題例: 共通データが壊れる
local Character = { health = 100 }
function Character.takeDamage(amount)
Character.health = Character.health - amount
print("Remaining health: " .. Character.health)
end
local player1 = Character
local player2 = Character
player1.takeDamage(20) -- 出力: Remaining health: 80
player2.takeDamage(30) -- 出力: Remaining health: 50
ここでは、player1
と player2
が同じ Character
テーブルを共有しているため、一方の操作がもう一方にも影響してしまいます。
5. self の正体を理解する
技術的に言うと、self
は単なる関数の最初の引数です。
以下の2つの書き方は同じ意味です:
function Object:sayHello()
print(self.name)
end
-- 実際にはこれと同じ
function Object.sayHello(self)
print(self.name)
end
つまり、「:」 は単に 最初の引数に自動的にそのオブジェクトを渡す記法 なのです。
6. self のまとめ
- 何を指す?
self
は関数を呼び出したオブジェクトそのもの。 - いつ使う?
オブジェクトに関連するデータやプロパティを操作するとき。 - どう便利?
- メソッドがどのオブジェクトで呼ばれたかを自動的に把握できる。
- 再利用性や柔軟性が向上する。
- コードがすっきりし、ハードコーディングを避けられる。