Fresh variables
Fresh variables
매크로가 코드를 생성할 때, 생성된 코드 안의 변수가 사용자 코드의 지역 변수와 우연히 충돌하는 일이 생길 수 있어요. 매크로 안에서 전용 변수를 쓰고 싶을 때 %name 문법으로 "신선한 변수(fresh variable)"를 선언할 수 있어요.
출처: Crystal 공식 문서
본문
매크로가 코드를 생성하면, 그 코드는 일반 Crystal 파서로 파싱되는데, 매크로 호출 문맥의 지역 변수가 정의되어 있다고 가정해요.
이것은 예시로 이해하는 게 좋아요.
macro update_x
x = 1
end
x = 0
update_x
x # => 1
이것은 반복 코드를 피하기 위해 지역 변수를 의도적으로 읽고/쓰는 데 유용할 때도 있지만, 실수로 지역 변수를 덮어쓸 수도 있어요. 이를 피하기 위해 %name으로 fresh variable을 선언할 수 있어요.
macro dont_update_x
%x = 1
puts %x
end
x = 0
dont_update_x # outputs 1
x # => 0
위 예시에서 %x를 쓰면, 현재 스코프의 지역 변수와 절대 충돌하지 않는 이름을 가진 변수를 선언하게 돼요.
추가로, 어떤 다른 AST 노드에 상대적인 fresh variable은 %var{key1, key2, ..., keyN}로 선언할 수 있어요. 예를 들어:
macro fresh_vars_sample(*names)
# First declare vars
{% for name, index in names %}
print "Declaring: ", stringify(%name{index}), '\n'
%name{index} = {{index}}
{% end %}
# Then print them
{% for name, index in names %}
print stringify(%name{index}), ": ", %name{index}, '\n'
{% end %}
end
macro stringify(var)
{{ var.stringify }}
end
fresh_vars_sample a, b, c
# Sample output:
# Declaring: __temp_255
# Declaring: __temp_256
# Declaring: __temp_257
# __temp_255: 0
# __temp_256: 1
# __temp_257: 2
위 예시에서 세 개의 인덱스 변수를 선언하고 값을 할당한 뒤 출력해서, 각각의 인덱스를 보여주고 있어요.
더 알아보기
%x는 사용자 지역 변수와 충돌하지 않는 고유한 이름의 변수를 만들어요.%var{key}형태를 쓰면 인덱스마다 서로 다른 fresh variable을 만들 수 있어요.- 매크로 관련 다른 내용은 매크로 문서에서 확인할 수 있어요.