0Pricing
Lua Academy · 강의

생성자와 new()

인스턴스를 만들고 초기화하는 생성자 함수를 작성합니다.

생성자와 new()은(는) CoddyKit의 무료 Lua Academy 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Lua Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Lua Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

생성자의 책임

생성자는 인스턴스를 만들고 초기화합니다. 초기값을 받고, 값을 검증하고, 누락된 필드에 기본값을 설정한 다음 새 인스턴스를 반환합니다. 잘 설계된 생성자는 모든 인스턴스가 유효한 상태에서 시작하도록 보장합니다.

local Player = {}
Player.__index = Player

function Player.new(name, hp, mp)
  assert(type(name)=="string" and name~="","need name")
  return setmetatable({
    name = name,
    hp   = hp or 100,
    mp   = mp or 50,
    alive = true,
    items = {},
  }, Player)
end

local p = Player.new("Hero")
print(p.name, p.hp, p.mp)  -- Hero  100  50

플루언트 생성자

플루언트 생성자는 설정자 메서드에서 self를 반환하여 생성 중 메서드 연쇄 호출을 가능하게 합니다. 이는 Lua의 빌더 패턴입니다.

local Config = {}
Config.__index = Config

function Config.new()
  return setmetatable({_data={}}, Config)
end

function Config:set(k,v) self._data[k]=v; return self end
function Config:build() return self._data end

local cfg = Config.new()
  :set("host","localhost")
  :set("port",8080)
  :set("debug",true)
  :build()

print(cfg.host, cfg.port)

복사 생성자

복사 생성자는 기존 인스턴스와 동일한 값으로 새 인스턴스를 만듭니다. 중요: 중첩된 테이블을 공유해야 하는지 독립적으로 복사해야 하는지에 따라 얕은 복사 또는 깊은 복사를 사용해야 합니다.

local function deepCopy(orig)
  if type(orig)~="table" then return orig end
  local copy = {}
  for k,v in pairs(orig) do copy[deepCopy(k)]=deepCopy(v) end
  return setmetatable(copy, getmetatable(orig))
end

local Item = {}
Item.__index = Item

function Item.new(name, stats)
  return setmetatable({name=name, stats=stats or {}}, Item)
end

function Item:clone()
  return deepCopy(self)
end

local sword = Item.new("Sword",{damage=50})
local clone = sword:clone()
clone.stats.damage = 30
print(sword.stats.damage)  -- 50 (unchanged)

검증을 포함한 생성자

생성자 입력값은 항상 검증해야 합니다. 잘못된 입력에 대해서는 2단계(호출자 책임)에서 내용을 설명하는 오류를 발생시키세요. 이렇게 하면 버그를 조기에 발견하고 유용한 오류 메시지를 제공할 수 있습니다.

local Rectangle = {}
Rectangle.__index = Rectangle

function Rectangle.new(w, h)
  assert(type(w)=="number" and w>0,"width must be positive number")
  assert(type(h)=="number" and h>0,"height must be positive number")
  return setmetatable({width=w, height=h}, Rectangle)
end

function Rectangle:area() return self.width * self.height end
function Rectangle:perimeter() return 2*(self.width+self.height) end

local r = Rectangle.new(5, 3)
print(r:area(), r:perimeter())  -- 15  16

기본값 패턴

선택적 생성자 매개변수를 깔끔하게 처리하려면 기본값 테이블을 사용하세요. 이렇게 하면 x = x or default를 길게 이어 쓰지 않아도 되고, 기본값이 명확해져 쉽게 변경할 수 있습니다.

local Sprite = {}
Sprite.__index = Sprite

local DEFAULTS = {x=0,y=0,rotation=0,scale=1,visible=true,alpha=1}

function Sprite.new(image, opts)
  local cfg = opts or {}
  local self = {image=image}
  for k,v in pairs(DEFAULTS) do
    self[k] = cfg[k] ~= nil and cfg[k] or v
  end
  return setmetatable(self, Sprite)
end

local s = Sprite.new("hero.png",{x=100,y=200})
print(s.x,s.y,s.scale)  -- 100 200 1

정적 팩토리 메서드

클래스에는 서로 다른 생성 상황을 위한 여러 팩토리 메서드가 있을 수 있습니다. 이는 선택적 매개변수가 많은 단일 생성자를 오버로드하는 것보다 깔끔합니다.

local Color = {}
Color.__index = Color

function Color.fromRGB(r,g,b)
  return setmetatable({r=r,g=g,b=b}, Color)
end

function Color.fromHex(hex)
  hex = hex:gsub("#","")
  return setmetatable({
    r=tonumber(hex:sub(1,2),16),
    g=tonumber(hex:sub(3,4),16),
    b=tonumber(hex:sub(5,6),16),
  }, Color)
end

function Color:toHex()
  return string.format("#%02X%02X%02X",self.r,self.g,self.b)
end

local red = Color.fromHex("#FF0000")
print(red:toHex())  -- #FF0000

생성자 레지스트리

모든 인스턴스를 추적하려면 레지스트리를 사용하세요. 그러면 "모두 삭제"와 같은 전역 작업을 수행하거나 특정 유형의 모든 객체를 순회할 수 있습니다.

local Enemy = {}
Enemy.__index = Enemy
Enemy._all = {}

function Enemy.new(name, hp)
  local self = setmetatable({name=name, hp=hp}, Enemy)
  Enemy._all[#Enemy._all+1] = self
  return self
end

function Enemy.destroyAll()
  for _, e in ipairs(Enemy._all) do
    print("Destroying:", e.name)
  end
  Enemy._all = {}
end

Enemy.new("Goblin",30)
Enemy.new("Orc",80)
print("Count:", #Enemy._all)  -- 2
Enemy.destroyAll()

지연 초기화

일부 필드는 계산 비용이 높습니다. __index와 함수를 사용하여 처음 접근할 때 해당 값을 계산하고 캐시하세요.

local BigData = {}
BigData.__index = function(t, k)
  if k == "processed" then
    print("Computing processed...")
    local result = {}
    for i,v in ipairs(rawget(t,"raw")) do result[i]=v*2 end
    rawset(t,"processed",result)
    return result
  end
end

function BigData.new(raw)
  return setmetatable({raw=raw}, BigData)
end

local d = BigData.new({1,2,3,4,5})
print(d.processed[3])  -- Computing...  6
print(d.processed[3])  -- 6 (cached, no recompute)

인스턴스로부터 프로토타입 만들기

인스턴스를 복제하여 동일한 기본값을 가진 다른 인스턴스를 만드세요. 복제본은 동일한 메타테이블(동일한 클래스)과 인스턴스 데이터의 사본을 얻습니다. "템플릿" 객체에 유용합니다.

local Unit = {}
Unit.__index = Unit

function Unit.new(t)
  return setmetatable({name=t.name,hp=t.hp,atk=t.atk}, Unit)
end

function Unit:clone()
  return Unit.new({name=self.name,hp=self.hp,atk=self.atk})
end

function Unit:__tostring()
  return self.name.."(HP:"..self.hp..",ATK:"..self.atk..")"
end

local template = Unit.new({name="Soldier",hp=100,atk=10})
local u1 = template:clone(); u1.name="Alpha"
local u2 = template:clone(); u2.name="Beta"
print(tostring(u1),tostring(u2))

생성자 오류 안전성

생성이 중간에 실패하는 경우(예: 자원 할당 실패), 불완전한 객체가 외부로 유출되지 않도록 해야 합니다. pcall을 사용하여 생성 오류를 포착하고 필요한 경우 자원을 정리하세요.

local FileHandle = {}
FileHandle.__index = FileHandle

function FileHandle.new(path, mode)
  local f, err = io.open(path, mode or "r")
  if not f then
    return nil, "cannot open " .. path .. ": " .. err
  end
  return setmetatable({_f=f, path=path}, FileHandle)
end

function FileHandle:read(fmt) return self._f:read(fmt) end
function FileHandle:close() self._f:close() end

local fh, err = FileHandle.new("data.txt")
if not fh then print("Error:", err)
else print(fh:read("l")); fh:close()
end

빠른 확인

Lua 객체 지향 프로그래밍에서 생성자(new())의 역할은 무엇인가요?

복습: 생성자

요약:

  • 생성자는 검증하고 초기화한 다음 setmetatable을 호출합니다
  • 선택적 매개변수를 깔끔하게 처리하려면 기본값 테이블을 사용합니다
  • 서로 다른 생성 상황에는 여러 팩토리 메서드를 사용합니다
  • 템플릿 객체에는 복제 생성자를 사용합니다
  • 계산 비용이 높은 필드에는 __index를 통한 지연 초기화를 사용합니다
  • 자원 할당에 실패하면 생성자에서 nil+err를 반환합니다

자주 묻는 질문

“생성자와 new()” 강의는 무료인가요?

네 — “생성자와 new()” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Lua Academy 강의 전체를 잠금 해제할 수 있습니다. Lua Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“생성자와 new()”에서 뭘 배우나요?

인스턴스를 만들고 초기화하는 생성자 함수를 작성합니다. 브라우저에서 직접 실행하는 실습 코드로 Lua Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

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

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

“생성자와 new()” 강의는 얼마나 걸리나요?

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

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

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

이 강의의 모든 강의

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