Perl의 데이터 타입: 스칼라·배열·해시와 시그널
Perl의 데이터 타입: 스칼라·배열·해시와 시그널
Perl의 데이터는 결국 셋 중 하나예요. 값 하나를 담는 스칼라, 값들을 순서대로 담는 배열, 그리고 키와 값 쌍으로 저장하는 해시가 전부죠. 이 세 타입을 어떻게 구분하는지, 이름 앞에 붙는 시그널($, @, %) 하나만 봐도 금방 알 수 있어요. 시그널은 변수의 종류를 알려주는 상징이라서, 코드를 읽을 때 가장 먼저 확인하게 되는 부분이에요.
본문
Perl은 세 가지 내장 데이터 타입을 가져요. 스칼라(scalar), 스칼라들의 배열(array), 그리고 '연관 배열'(associative array)이라 부르는 해시(hash)가 그 주인공이에요. 스칼라는 하나의 문자열(크기는 메모리가 허용하는 한 무제한)이거나 숫자, 또는 어떤 것을 가리키는 참조(reference)인데, 참조는 perlref에서 자세히 다뤄요.
배열은 0부터 세는 숫자 인덱스가 붙은 스칼라들의 순서 있는 목록이고, 해시는 문자열 키로 인덱싱된 스칼라 값들의 순서 없는 집합이에요.
시그널: $, @, %
변수 이름의 첫 글자는 그 이름이 어떤 종류의 데이터 구조를 가리키는지 알려줘요. 이 글자를 **시그널(sigil)**이라고 해요. 예를 들어 스칼라는 값 하나가 기대된다는 뜻으로, 마치 영어의 "the"처럼 동작하는 $ 시그널을 항상 붙여요. 배열이나 해시에 속한 스칼라 하나를 가리킬 때도 이름 앞에 $를 붙인답니다.
$days # 단순 스칼라 값 "days"
$days[28] # 배열 @days의 29번째 요소
$days{'Feb'} # 해시 %days의 'Feb' 값
$#days # 배열 @days의 마지막 인덱스
배열 전체(와 배열·해시의 슬라이스)는 @ 시그널로 나타내요. 이것은 영어의 "these"나 "those"처럼 여러 값이 기대된다는 뜻이에요.
@days # ($days[0], $days[1],... $days[n])
@days[3,4,5] # ($days[3],$days[4],$days[5]) 와 같음
@days{'a','c'} # ($days{'a'},$days{'c'}) 와 같음
해시 전체는 % 시그널을 써요.
%days # (key1, val1, key2, val2 ...)
서브루틴은 & 시그널로 이름을 붙이는데, 모호하지 않을 때는 생략해도 돼요. 그리고 각 변수 타입은 저마다 고유한 이름 공간을 가지므로, 같은 이름을 스칼라·배열·해시에 겹쳐 써도 충돌하지 않아요. 즉 $foo와 @foo는 서로 엄연히 다른 변수랍니다. 참고로 $foo[1]은 $foo의 일부가 아니라 @foo의 일부예요.
스칼라 값
Perl의 모든 데이터는 스칼라이거나 스칼라들의 배열·해시예요. 스칼라는 숫자·문자열·참조 셋 중 하나의 값을 담을 수 있고, 형태 사이 전환은 대개 투명하게 일어나요. 스칼라가 가진 참조를 통해 배열이나 해시의 여러 값을 간접적으로 담을 수도 있지요.
스칼라 값은 불리언 맥락에서 undefined이거나 빈 문자열, 또는 숫자 0(혹은 문자열 "0")이면 FALSE로 해석되고, 그 외에는 TRUE예요.
배열의 길이는 스칼라 값이에요. @days의 길이는 $#days로 알아낼 수 있는데, 주의할 점은 이게 배열의 길이가 아니라 마지막 요소의 인덱스라는 거예요 (보통 0번째 요소가 있으니까요). 배열을 스칼라 맥락에서 평가하면 길이를 돌려줘요. 해시를 스칼라 맥락에서 평가하면 비어 있으면 거짓, 키·값 쌍이 하나라도 있으면 참을 돌려줘요. Perl 5.25 이후로는 해시 안의 키 개수를 돌려주도록 바뀌었어요.
컨텍스트
Perl에서 연산의 해석은 주변 컨텍스트(맥락)에 따라 달라져요. 크게 리스트(list) 와 스칼라(scalar) 두 컨텍스트가 있고, 어떤 연산은 리스트를 원하는 자리에서는 리스트 값을, 그 외에는 스칼라 값을 돌려줘요. 마치 영어의 "fish"와 "sheep"이 단수·복수에서 형태가 같듯이, Perl은 기대되는 결과값이 단수냐 복수냐에 따라 연산을 겹쳐서(overload) 정의하기도 해요.
대입 연산은 왼쪽 피연산자로 오른쪽을 평가할 컨텍스트를 정해요. 스칼라에 대입하면 오른쪽이 스칼라 맥락에서 평가되고, 배열이나 해시에 대입하면 리스트 맥락에서 평가되죠.
슬라이스
배열이나 해시에서 여러 요소를 한 번에 뽑아낼 수 있어요. 슬라이스를 바꾸면 원래 배열·해시의 값이 바뀌기 때문에, foreach로 슬라이스를 순회하면 배열이나 해시의 값 일부(혹은 전부)를 수정할 수도 있어요.
foreach (@array[ 4 .. 10 ]) { s/peter/paul/ }
foreach (@hash{qw[key1 key2]}) {
s/^\s+//; # 앞 공백 제거
s/\s+$//; # 뒤 공백 제거
s/\b(\w)(\w*)\b/\u$1\L$2/g; # 단어 "타이틀케이스"화
}
슬라이스 하나를 헷갈리는 이유를 설명해볼게요. 키/값 슬라이스처럼 해시 슬라이스에 % 대신 @를 쓰는 걸 보고 이상하게 느낄 수 있는데, 간단해요. 대괄호([...])냐 중괄호({...})냐가 배열을 보는지 해시를 보는지를 정하고, 앞에 붙은 $나 @는 단수(스칼라) 값을 얻을지 복수(리스트) 값을 얻을지를 정해요. Perl 5.20부터는 % 기호를 쓰는 해시 슬라이스가 값만이 아니라 키·값 쌍 목록을 돌려주는 변형도 생겼어요.