[ 함수 (subroutine) ]
정의
perl에서는 함수를 일반적으로 subroutine이라고 부르며, 사용 시에는 함수 명 앞에 sub를 붙여준다.
-> sub subname{
statement 1;
statement 2;
}
* $fred, @fred, %fred와 서브루틴 fred 는 함께 존재할 수 있다
사용
① Perl에서는 서브루틴을 파일의 끝부분에 두는 것을 선호한다
② 서브루틴 내에서 전역변수 접근이나 값 할당이 가능하다
③ 서브루틴 이름과 뒤에 오는 괄호로써 서브루틴을 호출한다
④ 서브루틴은 다른 서브루틴을 호출할 수 있다
-> say_hello(); # 간단한 표현식
$a = 3 + say_hello(); # 더 긴 표현식의 일부
for ($x = start_value(); $x < end_value(); $x += increment()){
… # 값을 얻기 위해 3개의 서브루틴을 호출
}
리턴 값
① return으로 서브루틴의 호출 값을 되돌릴 수 있다
-> sub sum_of_a_and_b{
return $a + $b;
}
$a = 3; $b = 4;
$c = sum_of_a_and_b(); # $c 는 7
② 리스트 구문이 사용될 때는 값의 리스트를 리턴할 수 있다
-> sub list_of_a_and_b{
return($a, $b);
}
$a = 5; $b = 6;
@c = list_of_a_and_b(); # @c 는 (5, 6)
인수(arguments)
perl에서 서브루틴 호출은 괄호 내에 리스트가 뒤따르는데, 그 리스트는 서브루틴의 기간동안 자동으로 @_라는 특수한 변수에 할당된다. 서브루틴에서 이 변수에 접근하기 위해서는 $_[0], $_[1], $_[2]… 과 같이 사용한다
-> sub say_hello_to {
print “hello, $_[0]! ”; # 첫번째 매개변수가 목표
}
say_hello_to(“world”); # hello를 world에게
$x = “somebody”;
say_hello_to($x); # hello를 somebody에게
say_hello_to(“me”) + say_hello_to(“you”); # 그리고 me와 you에게
* 마지막 행에서 리턴 값은 실제로 사용되지 않았지만, 합을 계산하기 위해서 perl은
그것의 모든 부분을 계산해야 하므로 서브루틴을 두번 호출했다
-> sub say{
print “$_[0], $_[1]! ”;
}
say(“hello”, “world”); # 하나 이상의 인수를 사용하는 예
* 초과하거나 부족한 인수는 무시된다 (undef 값)
* $_[] 과 $_ 은 비슷하지만 아무런 관련이 없으므로 혼동하지 말 것!
함수 내의 사설 변수
my를 이용하여 동일하게 동작하는 사용자 자신의 스칼라, 배열, 해시 변수를 만들 수 있다
-> sub add{
my (%sum); # $sum 지역 변수로 만듦
$sum = 0; # sum을 초기화
foreach $_ (@_) {
$sum += $_; # 각 요소를 더함
}
return $sum; # 계산되는 마지막 식: 모든 요소의 합
}
* 전역변수 sum이 존재하더라도 add 서브루틴에서는 지역변수 sum을 쓸 수 있다
* 많은 중첩된 지역 변수 버전을 가질 수 있지만 한 순간에 오직 하나만 접근된다
-> sub bigger_than {
my($n, @values); # 몇몇 지역 변수를 생성
($n, @values) = @_; # args를 한계와 값으로 분리
my(@result); # return 값을 담을 임시 공간
foreach $_ (@values) { # args 리스트에 하나하나 적용
if ($_ > $n) { # 조건을 만족하는가?
push(@result, $); # 추가하라
}
}
return @result; # 마지막 결과를 리턴
}
@new = bigger_than(100, @list); # @new는 모든 @list > 100을 얻음
@this = bigger_than(5, 1, 5, 15, 30); # @this는 (15, 30)가 됨
my의 결과는 할당 가능한 리스트로 이것의 의미는 배열 할당 연산자의 왼쪽 편에 사용될 수 있다는 것이다. 이 리스트는 새로이 생성된 변수의 각각에 대해 초기값을 줄 수 있다.
-> my($n, @values);
($n, @values) = @_; # args를 한계와 값으로 분리
-> my($n, @values) = @_; # 위의 두 문장을 하나로 결합해서 사용 가능
-> my($sum) = 0; # 인수 없는 지역 변수를 초기화
* my는 선언문처럼 보이지만 실제로는 실행 연산자임을 주의
* my 연산자를 서브루틴 정의의 시작부분에 몰아 두는 것이 좋은 프로그래밍 방법이다
local을 이용한 준사설(semiprivate)변수
local변수는 그들 변수가 선언된 블록 내에서 호출 된 함수는 볼 수 있다
-> $value = “original”;
tellme(); spoof(); tellme();
sub spoof() {
local ($value) = “temporary”;
tellme();
}
sub tellme() {
print “Current value is $value ”;
}
출력 결과>
Current value is original # local 대신 my가 사용되었을 경우 $value를 읽는
Current value is temporary # 것은 spoof() 함수에서만 가능했을 것이다
Current value is original
파일레벨 my() 변수
use strict;
를 파일의 시작부에 둔다면 my()를 이용해 변수선언을 강제 할 수 있으며, my()로 선언되지 않은 변수는 에러를 낸다
-> use strict;
my $a; # undef로 시작
my @b = qw(fred barney betty); # 초기 값을 줌
push @b, qw(wilma);
@c = sort @b; # 컴파일되지 않는다
* 변수 선언을 강제하는 것의 이점 2가지
① 프로그램 실행이 빨라진다
(일반 변수보다 my로 생성된 변수가 좀 더 빨리 엑세스 된다)
② $fred가 필요할 때, 더 이상 존재하지 않는 이름의 $fred를 참조하지 않아도 되므로 타이핑 상의 오류를 훨씬 빨리 잡을 수 있다.
* 파일레벨 my()변수선언은 지역변수와는 다르다
[기타 제어 구조]
last
last문은 C의 break문과 같은 역할을 한다. 가장 안쪽의 루프 블록에서 빠져 나와 그 블록 바로 뒤에 오는 문에서 실행을 계속 하도록 한다
-> while (something) {
something;
if (somecondition) {
somethingorother;
last; # while 루프를 빠져나감
}
morethings;
}
# last는 이곳으로 옴
* last 문은 오직 루프 블록과 사용되며, 다른 문법 구조들을 만드는 데 필요한 다른 블록
들과는 사용되지 않는다. (if/else문은 고려 대상이 아님!)
next
next는 last와 비슷하지만, 블록을 마치지 않고 가장 안쪽 루프 블록의 나머지를 건너뛰어 실행하도록 한다.
-> while (something) {
firstpart;
if (somecondition) {
somepart;
next;
}
otherpart;
# next는 이곳으로 온다
}
redo
redo는 현재 블록의 시작부로 건너뛰도록 한다
-> while (somecondition) {
# redo는 이곳으로 온다
something;
if (somecondition) {
somestuff;
redo;
}
morething;
}
라벨붙이기
라벨을 정한 후, 블록을 포함하는 문 바로 앞 뒤에 콜론을 붙여서 위치시킨다
-> SOMELABEL: while (condition) {
statement;
if (nuthercondition) {
last SOMELABEL;
}
}
표현식 수정자
“if this, then that” 과 같은 방식으로 if문을 사용했던 것 과는 달리 perl은 다음과 같은 형식을 지원한다
some_expression if control_expression;
이것은 다음 예제와 동일하다
if (control_expression) {
some_expression;
}
-> LINE: while (<STDIN>) {
last LINE if /^From: /;
}
* unless, while, until도 이와 비슷하게 사용 가능하다
-> exp2 unless exp1; # unless (exp1) {exp2;} 와 유사
exp2 while exp1; # while (exp1) {exp2;} 와 유사
exp2 until exp1; # until (exp1) {exp2;} 와 유사
제어구조로서의 && 와 ||
다음과 같은 형식으로 제어구조로서 사용이 가능하다
* this && that; : if (this) {that};
-> this가 참이면, 여전히 전체 표현식의 값은 that에 의존하기 때문에 미정이다. 따라서
that이 계산되어야만 한다
-> this가 거짓이면, 이미 전체 표현식의 값은 거짓이 되므로 더 이상 that을 볼 필요가
없다. 따라서 that을 계산할 필요가 없으므로 이를 건너 뛴다
* this || that; : unless (this) {that};