Tải bản đầy đủ (.doc) (6 trang)

Tài liệu Ngôn ngữ Perl-Chương 08-Hàm pptx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (138.1 KB, 6 trang )

Learning Perl - Chương 8: Hàm
1. Xác định một hàm tiện ích
2. Gọi một hàm tiện ích
3. Giá trị trả về
4. Đối số của hàm
5. Biến cục bộ trong hàm
6. Bài tập
Chúng ta đều đã thấy và đã dùng các hàm được thiế kế sẵn (có sẵn) như chop, print...Bây giờ ta
hãy nhìn vào các hàm mà bạn định nghĩa ra, tạo nên các lệnh chương trình Perl.
8.1 Xác định một hàm tiện ích
Một hàm tự tạo, thường hay được gọi là chương trình con hay trình con, được xác định trong
chương trình Perl của bạn bằng việc dùng một kết cấu như:
sub subname {
cau lenh 1;
cau lenh 2;
cau lenh 3;
....
}
subname là tên của chương trình con, là bất kì tên nào giống như tên ta đã đặt cho biến vô
hướng, mảng và mảng băm (cho nên bạn có thể có một biến vô hướng $jerry, một mảng
@jerry, một mảng kết hợp %jerry, và bây giờ một trình con jerry.
Khối các câu lệnh đi sau tên trình con trở thành định nghĩa của trình con. Khi trình con được
gọi tới (được mô tả ngắn gọn), thì khối các câu lệnh tạo nên trình con này sẽ được thực hiện,
và bất kì giá trị trả về nào (được mô tả sau đây) đều được trả về cho nơi gọi.
Chẳng hạn sau đây là một trình con cho hiển thị câu nói nổi tiếng:
sub say_hello {
print "Xin chao moi nguoi!\n";
}
Định nghĩa trình con có thể ở bất kì đâu trong văn bản chương trình của bạn, nhưng bạn nên
đặt tất cả các trình con vào cuối tệp, để cho phần còn lại của chương trình có vẻ như là ở đầu
tệp. (Nếu bạn thích nghĩ theo kiểu Pascal thì bạn có thể đặt các trình con của mình vào đầu và


các câu lệnh thực hiện vào cuối).
Các định nghĩa trình con là toàn cục; không có trình con cục bộ. Nếu bạn có hai định nghĩa
trình con với cùng tên thì trình sau sẽ đè lấp trình trước mà không có cảnh báo gì cả.
Bên trong thân trình con, bạn có thể thâm nhập hay đặt các giá trị cho các biến được dùng
chung với phần còn lại của chương trình (biến toàn cục). Trong thực tế, theo mặc định, mọi
tham khảo biến bên trong thân trình con đều tham khảo tới biến toàn cục. Nhưng bạn có thể
dùng các biệt lệ trong mục "Biến cục bộ trong hàm" ở dưới đây. Trong thí dụ sau:
sub say_what {
print "Xin chao, $what\n";
}
$what tham khảo tới giá trị toàn cục cho $what và được dùng chung với phần còn lại của
chương trình.
8.2 Gọi một hàm tiện ích
Bạn gọi một trình con từ bên trong bất kì biểu thức nào bằng việc ghi ra tên của chương trình
con và theo sau là danh sách các tham số được đặt trong hai dấu ngoặc (), như kiểu thế này:
say_hello(); #mot bieu thuc don gian
$a = 3 + say_hello(); #mot bieu thuc kep
for ($x = start_value(); $x < end_value(); $x += increment()) {
...
} #goi 3 trinh con
Một trình con có thể gọi một trình con khác, và trình con khác này đến lượt nó lại có thể gọi
trình con khác nữa, và cứ như thế, cho tới khi tất cả bộ nhớ có sẵn đã bị chất đầy bằng địa chỉ
quay về và các biểu thức được tính toán hết.
8.3 Giá trị trả về
Giống như trong C, một trình con bao giờ cũng là một phần của một biểu thức nào đó (không
có cái tương đương trong lời gọi thủ tục tựa Pascal. Chắc chắn là như thế!!!). Giá trị của việc
gọi trình con được gọi là giá trị trả lại. Giá trị trả lại của một trình con là giá trị của biểu thức
cuối cùng được tính bên trong thân của trình con cho mỗi lần gọi.
Chẳng hạn, ta hãy định nghĩa trình con này:
sub sum_of_a_and_b {

$a + $b;
}
Bạn cũng có thể dùng câu lệnh return để trả về giá trị từ trình con:
sub sum_of_a_and_b {
return $a + $b;
}
Biểu thức cuối cùng được tính trong thân của trình con này (trong thực tế, đó là biểu thức duy
nhất được tính) là tổng của $a và $b, cho nên tổng của $a và $b sẽ là giá trị cho lại. Sau đây là
thí dụ:
$a = 3; $b = 4;
$c = sum_of_a_and_b(); #$c = 7
$d = 3*sum_of_a_and_b(); #$d = 21
Một trình con cũng có thể cho lại một danh sách các giá trị khi được tính trong hoàn cảnh
mảng. ta hãy xét trình con này và lời gọi:
sub list_of_a_and_b {
($a, $b);
}
$a = 3; $b = 4;
@c = list_of_a_and_b(); #@c = (5, 6)
Biểu thức cuối được tính thực sự nghĩa là biểu thức cuối cùng được tính, thay vì là biểu thức
cuối cùng được xác định trong thân của trình con. Chẳng hạn, trình con này cho lại $a nếu $a >
0, ngoài ra nó cho $b:
sub gime_a_or_b {
if ($a > 0) {
print "chon a ($a)\n";
$a;
} else {
print "chọn b ($b)\n";
$b;
}

}
Lưu ý rằng trình con này cũng cho hiển thị một thông báo. Biểu thức cuối cùng được tính là $a
hay $b, mà trở thành giá trị cho lại. Nếu bạn đảo ngược các dòng có chứa $a và print ngay
trước nó, thì bạn sẽ nhận được một giá trị cho lại là 1 (giá trị được cho lại bởi hàm print thành
công) thay vì giá trị của $a.
Tất cả chúng đều là các thí dụ khá đơn giản. Tốt hơn cả là ta nên truyền các giá trị khác nhau
cho mỗi lần gọi tới một trình con thay vì phải dựa vào các biến toàn cục.
8.4 Đối số của hàm
Mặc dù các trình con có một chức năng đặc biệt là có ích, toàn bộ mức độ có ích mới trở thành
sẵn có cho bạn khi bạn có thể truyền các đối số cho trình con. Trong Perl nếu lời gọi trình con
có theo sau nó một danh sách nằm trong ngoặc tròn, thì danh sách này dẽ được tự động gán cho
một biến đặc biệt có tên @_ trong suốt thời gian hoạt động của trình con. Trình con có thể
thâm nhập vào biến này để xác định số các đối và giá trị của các đối đó. Chẳng hạn:
sub say_hello_to {
print "Hello, $_[0]!\n"; #tham bien dau la muc tieu
}
Tại đây ta thấy một tham khảo tới $_[0], chính là phần tử đầu tiên của mảng @_. Lưu ý đặc
biệt: tương tự như dáng vẻ của chúng, giá trị $_[0] (phần tử đầu tiên của mảng @_) chẳng có
bất kì liên quan gì với biến $_ (một biến vô hướng của riêng nó). Bạn đừng lầm lẫn chúng! Từ
chương trình này, rõ ràng nó nói hello với bất kì cái gì chúng ta truyền cho nó như tham biến
đầu tiên. Điều đó có nghĩa là chúng ta có thể gọi nó giống thế này:
say_hello_to("world"); # se in ra Hello, world!
$x = "somebody";
say_hello_to($x); # Hello, somebody!
say_hello_to("me") + say_hello_to("you");
Lưu ý rằng trong dòng cuối, giá trị cho lại không thực sự được dùng. Nhưng trong khi tính
tổng Perl phải tính tất cả các bộ phận của nó, cho nên trình con này được gọi hai lần.
Sau đây là một thí dụ về việc dùng nhiều hơn một tham biến:
sub say {
print "$_[0], $_[1]!\n";

}
say("hello", "world"); #hello, world!
say ("goodbye", "cruel world");
Các tham biến vượt quá đều bị bỏ qua - nếu bạn chưa bao giờ xem tới $_[3], thì đối với Perl
cũng không sao. Các tham số không đủ cũng bị bỏ qua - bạn đơn thuần nhận được undef nếu
bạn nhìn vượt ra phần tử cuối của mảng @_, như với mọi mảng khác.
Biến @_ là cục bộ cho trình con này; nếu có một biến toàn cục cho @_, nó sẽ được cất giữ
trước khi trình con được gọi và được khôi phục lại giá trị trước của nó khi trở về từ chương
trình con. Điều này cũng có nghĩa là một trình con có thể truyền các đối cho một trình con khác
mà không sợ mất biến @_ riêng của nó - việc gọi trình con lồng nhau đều nhận được @_ riêng
của nó theo cùng cách.
Ta hãy xem xét lại trình con "cộng a và b" của mục trước. Tại đây một trình con thực hiện việc
cộng hai giá trị bất kì, đặc biệt, hai giá trị được truyền cho trình con này như tham biến.
sub add_two {
$_[0] + $_[1];
}
print add_two(3, 4); #in 7
$c = add_two(5, 6); #$c = 11
Bây giờ ta hãy tổng quát hoá chương trình này. Nếu chúng ta có ba, bốn hay hàng trăm giá trị
cần phải cộng lại thì sao? Chúng ta có thể làm việc đó bằng một chu trình, tựa như:
sub add {
$sum = 0 ; #khoi dong gia tri cho $sum
foreach $_ (@_ ) {
$sum += $_ ; #cong tung phan tu
}
$sum ; #bieu thuc cuoi duoc tinh: tong cua tat ca cac
phan tu,
#hoac ban co the dung return $sum;
}
$a = add(4,5,6) ; #cong 4+5+6 = 15, va gan cho $a

print add(1,2,3,4,5) ; #in ra 15
print add(1..5); #cung in ra 15, vi 1..5 duocc mo rong thanh
1,2,3,4,5
Điều gì xảy ra nếu ta có sẵn một biến mang tên $sum trước khi khi ta gọi hàm add_list? Trong
mục tiếp theo chúng ta sẽ xem cách thức tránh điều này.
8.5 Biến cục bộ trong hàm
Chúng ta đã nói tới biến @_ và cách thức việc sao chép cục bộ được tạo ra cho từng trình con
có gọi tới tham biến. Bạn có thể tạo ra các biến vô hướng, mảng hay mảng kết hợp của riêng
mình làm việc theo cùng cách. Bạn làm điều này với toán tử local() hoặc my(), local và my
nhận một danh sách các tên biến và tạo ra các bản cục bộ của chúng (hay các thể nghiệm). Sau
đây lại là hàm cộng ở trên, lần này dùng my():
Chú ý: Theo tài liệu của Per 5, bạn nên dùng my thay vì local.
sub add {
my $sum = 0 ; #tao bien cuc bo $sum va khoi tao gia tri
foreach $_ (@_ ) {
$sum += $_ ; #cong tung phan tu
}
return $sum; #tra ve ket qua
}
$a = add(4,5,6) ; #cong 4+5+6 = 15, va gan cho $a
print add(1,2,3,4,5) ; #in ra 15
print add(1..5); #cung in ra 15, vi 1..5 duocc mo rong thanh
1,2,3,4,5
Khi câu lệnh thân đầu tiên được thực hiện (lệnh my), thì bất kì giá trị hiện tại nào của biến toàn
cục $sum cũng đều được cất giữ và một biến mới mang tên $sum sẽ được tạo ra (với giá trị
undef). Khi chương trình con kết thúc, Perl bỏ qua biến cục bộ và khôi phục giá trị trước (toàn
cục) của $sum. Điều này vận hành cả khi biến $sum hiện là biến cục bộ của một trình con khác
(một trình con mà gọi tới trình con này, hay một trình con gọi tới một trình mà gọi tới trình con
này...). Các biến có thể có nhiều bản cục bộ lồng nhau, mặc dầu bạn có thể thâm nhập mỗi lúc
chỉ vào một biến.

Sau đây là cách để tạo ra một danh sách tất cả các phần tử có giá trị lớn hơn 100 của một mảng
lớn:
sub bigger_than_100 {
my (@result);
foreach $_ (@_ ) { #duyet qua danh sach
if ($_ > 100) { #kiem tra xem co lon hon 100?
push (@result, $_); #day vao danh sach
}
return @result ; #tra ve ket qua
}
Điều gì xảy ra nếu chúng ta muốn tất cả các phần tử này lớn hơn 50 thay vì 100? Chúng ta phải
sửa chương trình này, đổi tất cả các số 100 thành 50. Nhưng điều gì xảy ra nếu chúng ta lại cần
cả hai? Được, chúng ta có thể thay thế 50 hay 100 bằng một biến tham khảo. Điều này làm
chương trình trông giống thế này:
sub bigger_than {
my ($n, @values); #tao ra cac biet cuc bo
($n, @values) = @_; #khoi tao gia tri cho bien cuc bo,
thuc chat la lay gia tri tu cac tham so
my (@result); #them 1 bien cuc bo nua
foreach $_ (@values) { #duyet danh sach cac gia tri
if ($_ > $n) { #phan tu nay co gia tri lon hon $n
(=50, 100 hay gia tri nao do)
push (@result, $_) ; #dua vao danh sach neu hop le
}
return @result; #tra ve ket qua
}
#vi du
@new = bigger_than(100, @list); #tim cac phan tu lon hon 100 trong
mang @list
@this = bigger_than(5,1,5,15,30); #tim cac phan tu lon hon 5 trong

danh sach, ket qua la (15, 30)

×