250818

lililllilillll·2025년 8월 18일

개발 일지

목록 보기
267/350

✅ 한 것들


  • R&D : Lua, Neovim


🛠️ R&D


Lua

개념

  • print 'hello' 파라미터 한 개면 괄호 생략 가능

_G

-- _G는 모든 전역 변수에 대한 전역 테이블
print(_G['_G'] == _G) -- _G 자기 자신 역시 전역 변수이니 _G에 등록돼있다

다중 대입

x, y, z = 1,2,3,4
-- 1,2,3이 각각 대입되고, 4는 버려짐
-- 왼쪽이 더 많으면 넘친 것들은 nil

함수 선언

-- 함수 선언 1 : 둘 다 같다.
function f(x) return x*x end
f = function(x) return x*x end

-- 함수 선언 2 : 둘 다 같다. local을 붙였기 때문에 자기 참조가 가능해진다.
local function g(x) return math.sin(X) end
local g; g = function(x) return math.sin(x) end

테이블

-- 유일한 복합 자료형. 숫자 키 연속 저장하면 배열에, 문자열이나 비연속은 해시 테이블에 저장
t = {key1 = 'value1', key2 = false}
t.newKey = {} -- [newKey] 추가
t.key2 = nil -- table에서 key2 제거

-- nil만 아니면 죄다 키로 들어갈 수 있다
u = {['#@@'] = 'qbert', [{}] = 1729, [6.28] = 'tau'} 

print (u[{}])
-- 하지만 이건 nil을 출력한다.
-- 이번 {}는 key로 들어갔던 {}와 다르기 때문이다
-- 정 넣고 싶으면 변수를 이용해야 함
-- 테이블 하나만 인자로 들어가면 () 괄호 생략 가능
function h(x) print(x.key1) end
h{key1 = 'Sonmi~451'}  -- Prints 'Sonmi~451'.
-- 테이블 순회
for key, val in pairs(u) do
    print(key, val)
end

v = {'value1', 'value2', 1.33, 'gigawatts'}
for i = 1, #v do -- #v는 v의 크기를 의미
    print(v[i])
end

모듈

-- mod.lua 파일을 실행하여 결과값 반환받는다
local mod = require('mod') 

-- mod.lua에 있는 내용들을 익명 함수로 가져온 뒤
-- 익명 함수를 실행해서 값들을 반환받고
-- 그 결과들을 mod에 넣는다

-- 실제 이뤄지는 작업
-- local mod = (funtion ()
--     <contents of mod.lua>
-- end)()

기본 개념

-- mod가 객체(를 흉내낸 테이블)를 반환하는 코드를 담아놨다면 
local a = require("mod")  -- mod.lua 실행됨
local b = require("mod")  -- 실행 안 됨, 캐시된 값 반환
b.changeA()
print(a.returnA())
print(b.returnA()) 
-- require는 반환값을 캐싱하기 때문에 모듈 단위의 싱글톤을 만든다
-- 모듈 내부 local은 모듈 전체가 공유한다는 뜻
-- 고로 두 print 문 모두 같은 값을 출력한다
-- 독립 상태가 필요하면 팩토리(생성자) 패턴으로 인스턴스를 만들어야 한다
-- 그냥 값을 변수에 반환 받은 후에 따로 연산하면 당연히 별개 연산됨

캐싱된 값 반환 여러 번 받아도 동일한 객체

-- require은 캐싱하므로 두 번 실행 안 하고,
local a = require('mod2')  -- Prints Hi!
local b = require('mod2')  -- Doesn't print; a=b.
-- dofile은 캐싱 안 하므로 호출 때마다 계속 실행한다
dofile('mod2.lua')  --> Hi!
dofile('mod2.lua')  --> Hi! (runs it again)
-- loadfile은 실행 안 하고 로드만 해놓는다
f = loadfile('mod2.lua') --> f()로 실행
-- 그냥 load는 string 코드를 담아놓는다
g = load('print(343)')
g() --> 343

require, dofile, loadfile, load 차이점

클로저

function adder(x)
    -- 익명 함수 : 이름 없이 만든 함수
    -- 클로저(closure) : 자기 바깥 스코프의 변수 (이 경우엔 x) 를 기억한 채로 반환된다.
    -- 이때 값 복사가 아니라 참조를 들고간다. (똑같아지는거 해결하려면 local 변수 선언)
    return function (y) return x + y end
end

a1 = adder(9) --> 9 + y를 반환
a2 = adder(36) --> 36 + y를 반환
print(a1(16)) --> 25
print(a2(64)) --> 100

문법

for문

karlSum = 0
for i=1, 100 do
    karlSum = karlSum + i
end -- 5050

metatable

f1 = {a=1, b=2}
f2 = {a=2, b=3}

metafraction = {}
-- metafraction이라는 테이블 안에 __add 키 안에 함수를 넣음
-- setmetatable을 이용하면 __add 쓸 때 호출될 함수로 사용됨
function metafraction.__add(f1, f2) 
    sum = {}
    sum.b = f1.b * f2.b -- sum.b는 sum[b]와 동일
    sum.a = f1.a * f2.b + f2.a * f1.b
    return sum
end

-- f1 테이블에 metafraction이라는 규칙집이 적용됨 (f1에 저장하는 건 아님)
setmetatable(f1, metafraction) 
setmetatable(f2, metafraction)

s = f1 + f2 -- s.a == 7, s.b == 6
defaultFavs = {animal = 'gru', food = 'donuts'}
myFavs = {food = 'pizza'}
setmetatable(myFavs, {__index = defaultFavs}) -- 없는 키는 __index에서 찾아라
eatenBy = myFavs.animal
print(eatenBy) -- gru 출력
-- __add(a, b)                     for a + b
-- __sub(a, b)                     for a - b
-- __mul(a, b)                     for a * b
-- __div(a, b)                     for a / b
-- __mod(a, b)                     for a % b
-- __pow(a, b)                     for a ^ b
-- __unm(a)                        for -a
-- __concat(a, b)                  for a .. b
-- __len(a)                        for #a
-- __eq(a, b)                      for a == b
-- __lt(a, b)                      for a < b
-- __le(a, b)                      for a <= b
-- __index(a, b)  <fn or a table>  for a.b
-- __newindex(a, b, c)             for a.b = c
-- __call(a, ...)                  for a(...)

metatable에 쓰일 metamethod들

테이블로 클래스 흉내내기

Dog = {} -- table로 class를 흉내낸다

-- Dog:new()에서 콜론은 첫 번째 인자 self에 자동으로 Dog 넣음
-- 즉, Dog.new(self, ...)와 같다
function Dog:new() 
    newObj = {sound = 'woof'} -- Dog의 인스턴스가 될 테이블
    self.__index = self -- self의 __index 규칙 : self에서 찾아라
    return setmetatable(newObj, self) -- newObj에서 못 찾으면 self에서 찾는 규칙 적용
end

function Dog:makeSound() -- Dog에 self가 첫 번째 인자인 makeSound 함수가 등록됨
    print('I say ' .. self.sound)
end

mrDog = Dog:new() -- setmetatable은 주어진 첫번째 인자를 반환함
mrDog:makeSound()
LoudDog = Dog:new()

function LoudDog:makeSound() -- LoudDog에 있던 Dog의 makeSound()를 override
    s = self.sound .. ' '
    print(s .. s  .. s)
end

seymour = LoudDog:new()
seymour:makeSound() -- woof woof woof 

-- 생성자도 override 가능하다
-- 이러면 LoudDog에 메서드같은거 추가해도 Dog에는 반영 안됨
function LoudDog:new()
    newObj = {}
    self.__index = self
    return setmetatable(newObj, self)
end

상속 구현 예시

Neovim

https://youtu.be/KYDG3AHgYEs?si=_NNhP1R4zc3CELDI

window에선 config 폴더를 뭐로 대체? : C:\Users\사용자명\AppData\Local

https://learnxinyminutes.com/lua/ 여기서 lua 배워오라고 함 -> 이틀에 걸쳐 학습 완료

init 파일에 다른 파일들을 import하려면 lua 폴더를 만들어 거기에 import할 파일 넣어야 한다 (필수)

  • init.luarequire 'options' 해두고 lua 폴더에 options.lua 파일 만들고 거기에 config 적으면 된다는 뜻

https://github.com/nvim-lua/kickstart.nvim 여기서 kickstart 설치하라고 함

  • windows에는 kickstart 설치해도 오류가 없던 상황
  • 원래의 목적이었던 ec2 인스턴스로 돌아가 nvim을 다시 켜보니 역시 오류가 발생
  • readme를 다시 끝까지 읽어보니 ubuntu용 neovim 설치 명령어가 있었음
  • 그거 하고 kickstart clone 하니까 정상적으로 설치되고 오류도 사라짐
  • 뭔가 안되면 가장 먼저 매뉴얼을 끝까지 읽는 습관을 들이자
  • 목적은 벌써 달성했지만 사용법 익히기 위해 마저 수강해보기
profile
너 정말 **핵심**을 찔렀어

0개의 댓글