0Pricing
Lua Academy · 강의

인스턴스 메서드와 self

콜론 구문과 암시적 self 매개변수를 사용해 메서드를 정의합니다.

인스턴스 메서드와 self은(는) CoddyKit의 무료 Lua Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 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 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)  -- 15

믹스인 메서드

공식적인 상속 없이 믹스인 테이블의 메서드를 클래스에 추가하세요. 이는 평면 조합으로, 믹스인의 함수를 클래스 테이블에 복사하거나 참조하는 방식입니다.

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/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Lua Academy 강의 전체를 잠금 해제할 수 있습니다. Lua Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“인스턴스 메서드와 self”에서 뭘 배우나요?

콜론 구문과 암시적 self 매개변수를 사용해 메서드를 정의합니다. 브라우저에서 직접 실행하는 실습 코드로 Lua Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Lua Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Lua Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.

“인스턴스 메서드와 self” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Lua Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Lua Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 메타테이블을 이용한 클래스
  2. 생성자와 new()
  3. 인스턴스 메서드와 self
  4. 클로저를 이용한 캡슐화
← Lua Academy(으)로 돌아가기