4 minute read

Perl의 변수 유형

Perl에서는 세 가지 기본 변수 유형이 있습니다. $, %, @를 사용하여 변수를 처리할 수 있습니다. 그러나 복잡한 구조를 나타내기 위해서는 보다 복잡한 코드 구조가 필요합니다. Perl에서는 언어의 부가적인 문법을 알아야 코드 작성이 수월합니다.

기본 사용법

$ 연산자

일반적인 언어에서 숫자 또는 문자열만을 다루는 유형입니다. 스칼라 연산이라고도 하며, 스칼라는 방향성이 없음을 의미합니다. 값 자체를 가져오는 데 사용됩니다.

$var = 1;
$var2 = "string";
$var3 = 333;

print "$var, $var2, $var3";

위와 같이 사용할 수 있습니다.

@ 배열

@는 배열 타입을 나타내는 명령어입니다. 배열 타입으로 혼동하지 않도록 @를 사용합니다.

@arr = ("my", "name", "is", "ksoo"); 

print "$arr[0], $arr[1], $arr[2], $arr[3]\n";

배열 초기화를 위해서는 @를 사용하여 변수를 선언하고, 원하는 값을 괄호 사이에 넣습니다. 값을 접근하려면 @ 대신 $를 사용합니다.

배열의 길이를 구하려면 @arr를 사용합니다.

$arrLength = @arr;
print $arrLength;

명확하게 표현하고 싶은 Perl 프로그래머는 다음과 같이 사용할 수 있습니다.

% 해시

%는 딕셔너리(해시) 타입을 나타냅니다.

%name2email = (
  "ksoo" => "ksoo@gmail.com",
  "gsoo" => "gsoo@gmail.com",
  "young" => "young@gmail.com"
);

print "$name2email{ksoo}\n";
print "$name2email{gsoo}\n";

이러한 구조로 선언은 간단합니다. keys 함수로 키만 뽑아낼 수도 있으며, 뽑아낸 키를 sort로 정렬도 가능합니다. 저장된 값을 얻어올 때는 $ 연산자를 사용해야 합니다. 이는 값 자체가 스칼라이기 때문입니다.

기본을 넘어서

기본만 알고 모든 것을 할 수 있다면 다행이겠지만, 기본을 넘어서야 하는 일도 생깁니다. 여기서는 조금 복잡한 자료구조를 Perl로 표현하는 방법을 살펴봅니다.

배열과 해시는 서로 변환이 가능합니다. 앞서 보았던 코드를 보겠습니다.

%name2email = (
  "ksoo" => "ksoo@gmail.com",
  "gsoo" => "gsoo@gmail.com",
  "young" => "young@gmail.com"
);

@arr = %name2email;

다음과 같은 출력 결과를 확인할 수 있습니다.

$VAR1 = [
  'young',
  'young@gmail.com',
  'ksoo',
  'ksoo@gmail.com',
  'gsoo',
  'gsoo@gmail.com'
];
$VAR1 = {
  'young' => 'young@gmail.com',
  'ksoo' => 'ksoo@gmail.com',
  'gsoo' => 'gsoo@gmail.com'
};

배열의 인덱스 접근은 []를 이용하고, 해시의 접근은 {}로 한다는 사실을 기억해야 합니다.

레퍼런스와 복잡한 자료구조

이미 소개된 @, $, %를 이용하여 모든 자료구조를 표현할 수 있을 것 같지만, 한 가지 빠진 조건이 있습니다. Perl은 배열이든 해시든 스칼라 값만을 원소로 가집니다.

예를 들어,

@arr = ("ksoo", "gsoo");
@values = (1, 2, 3, 4, 5);
$arr[1] = @values;

위 코드의 의도했던 바는

$VAR1 = [
  'ksoo',
  [
    1,
    2,
    3,
    4,
    5
  ]
];

와 같을 것입니다. 하지만 결과는 [‘ksoo’, 5] 라는 참혹한 결과를 가지게 됩니다. @values라는 표현식은 scalar @values라는 표현식의 줄임이고, scalar @values@values 배열의 크기를 리턴합니다.

우리가 원하는 동작을 하게 하려면 어떻게 해야 할까요? Perl에서는 레퍼런스(\)가 있습니다. \ 뒤에 오는 표현식의 레퍼런스를 반환합니다.

$var1 = "test string";
$var2 = \$var1;

print "$var2\n";
print "${$var2}\n";
print "$$var2\n";

$$var2 = "hello reference";
print "-----------------\n";
print "$var1\n";

결과는 다음과 같습니다.

SCALAR(0x1538050)
test string
test string
-----------------
hello reference

$var2를 출력하고자 했는데 이 값은 SCALAR의 레퍼런스라고 나옵니다. 레퍼런스의 값을 알기 위해서는 레퍼런스 종류에 대한 기호를 쓰고, {}으로 감쌉니다. 표현이 명확할 때는 ${$var}로 쓰지 않고 $$var로 써도 인식합니다. 그리고 $$var2를 고쳐본 결과 예상한 대로 원본 $var1의 값이 바뀌었음을 알 수 있습니다.

@language = ("C", "C++", "Java", "Perl", "python");
$arrayRef = \@language;

print ${$arrayRef}[0]; 
print $$arrayRef[0];
print $arrayRef->[0];

$arrayRef는 단순히 @language의 주소만을 가지고 있습니다. Perl 5.6부터 sigil{var}->로 대체 가능합니다. -> 디레퍼런스 연산자는 기존의 sigil을 이용한 방식보다 훨씬 직관적으로 변수의 값을 읽게 해줍니다.

여기서 C를 출력하려면 일단은 스칼라이므로 sigil$가 됩니다.

>$

디레퍼런스 해야 하니까

${$arrayRef}

0번째 요소를 가져와야 하니까

${$arrayRef}[0]

여기서 {}를 제외하면

$$arrayRef[0]

$arrayRef는 arrayRef->로 대체 가능하다고 했습니다.

$arrayRef->[0]

익명 배열, 익명 해시

복잡한 sigil에 앞서 익명 배열과 익명 해시에 대해서 간략하게 알아야 합니다.

$arrayRef = ["C", "C++", "Java", "Perl", "python"];

위에서 썼던 @을 이용해서 배열을 만들고 레퍼런스를 대입했던 게 기억날 것입니다. 변수를 만들지 않고 바로 대입하려면 익명 배열을 써야 하는데 []를 사용합니다. []는 배열을 생성 후 배열의 주소를 리턴합니다.

마찬가지로 익명 해시는 {}으로, 해시 변수를 생성하고 레퍼런스를 리턴합니다.

조금 더 어려운 내용

$arrayRef=["C++","JAVA","Perl", [5, 4, 3, 2, 1]];

에서 5를 읽어내고 싶다면 어떻게 할까요? $arrayRef에 주소값이 들어가는데 그 주소값의 내용은 배열이고, 배열의 안의 3 인덱스 값 또한 주소로 들어가 있습니다. 구조가 바로 머리에 잡혀야 합니다.

먼저 sigil$

$

디레퍼런스해서 3번째 값을 읽어야 하니까

$arrayRef->[3]

여기서 다시 디레퍼런스해서 0번째 값

$arrayRef->[3]->[0]

연속 디레퍼런스일 때는 ->가 생략이 가능합니다.

$arrayRef->[3][0]

마치 2차원 배열처럼 쓸 수 있습니다.

$arrayRef=["C++","JAVA","Perl", [5, 4, 3, 2, 1]];

print "$arrayRef->[3]->[0]\n";
print "${$arrayRef->[3]}[0]\n";
print "${${$arrayRef}[3]}[0]\n";
print "${$$arrayRef[3]}[0]\n";
print "${$arrayRef->[3]}[0]\n";
print "$arrayRef->[3][0]\n";

6개 모두 같은 표현입니다. 잘 살펴보면 마지막 표현이 얼마나 직관적인지 느낌이 올 것입니다. ->를 적극적으로 사용하세요.

$object = [ 10, 20, 30, [100, { 300 => [1,2, { 3=>7 } ] } ] ];

이제 $object에서 마지막 7을 출력해보겠습니다. 조금 멍해질 수 있는데 정신 차리고 보기 좋게 만들어봅시다.

$VAR1 = [
  10,
  20,
  30,
  [
    100,
    {
      '300' => [
        1,
        2,
        {
          '3' => 7
        }
      ]
    }
  ]
];

구조가 좀 눈에 보입니다. 일단은 스칼라 값을 가져와야 하니까

$

이제 슬슬 반복하다 보니 익숙해지지 않습니까? 순서대로 3 인덱스, 1 인덱스

$object->[3][1]

‘300’이라는 해시키를 만났으니

$object->[3][1]{300}

해시키의 값은 배열이므로

$object->[3][1]{300}[2]

여기서 다시 해시 디레퍼런스

$object->[3][1]{300}[2]{3}

마침내 7을 출력합니다.

이 과정을 따라왔다면 아마도 Perl의 레퍼런스 관련된 내용에서 헷갈리더라도 혼자 해결할 수 있는 능력을 갖췄을 것이라 믿습니다. 각종 서적에서 Perl이 쉽다고 하지만 레퍼런스와 디레퍼런스 관련된 내용은 그리 이해하기 쉽지 않으며, 한번에 잘 쓰기도 쉽지 않습니다. 나 또한 헷갈리는 것이 많았고, 나중에 다시 봤을 때 헷갈리지 말자고 정리했습니다. Perl을 배우는 많은 이들에게 도움이 됐으면 합니다.

Updated: