Tải bản đầy đủ (.docx) (7 trang)

Hàm

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 (67.97 KB, 7 trang )

Hàm
Hàm hệ thống và hàm ngời dùng
Chúng ta đều đã thấy và đã dùng các hàm hệ thống, nh chop, print vân vân. 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.
Xác định một hàm ngời dùng
Một hàm ngời dùng, 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 {
câu lệnh 1;
câu lệnh 2;
câu lệnh 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 kết hợp. Một lần nữa, những tên này lại đến từ một
không gian tên khác, cho nên bạn có thể có một biến vô hớng $fred, một mảng @fred,
một mảng kết hợp %fred, và bây giờ một trình con fred.
Khối các câu lệnh đi sau tên trình con trở thành định nghĩa của trìn hcon. 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ị cho lại 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 chào, mọi ngời!\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
(chúng bị bỏ qua khi thực hiện), nhng tôi thì thích đặt tất cả các trình con của tôi 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. Điều đấy thì tuỳ bạn.)
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. Tôi mách bạn về 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 chào, $what\n;
}
$what tham khảo tới giá trị toàn cục cho $what mà đợc dùng chung với phần còn
lại của chơng trình.
Gọi một hàm ngời dùng
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 đặt trớc tên
trình con này một dấu và &, nh trong:
&say_hello; # một biểu thức đơn giản
$a = 3 + &say_hello; # phần của biểu thức lớn hơn
for ($x = &start_value; $x < &end_value; $x += &increment) {
...
} # gọi ba trình con để xác định các giá trị
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 bộ phận. (Không có tám hay
32 mức nào có thể thoả mãn đợc cho ngời mê Perl.)
Giá trị cho lại
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). Giá trị của việc gọi trình
con đợc gọi là giá trị cho lại. Giá trị cho 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;
}
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à ffiều đó trong hành động:
$a = 3; $b = 4;
$c = &sum_of_a_and_b; #c nhận 7
$d = 3*sum_of_a_and_b; # $d nhận 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 = 5; $b = 6;
$c = &list_of_a_and_b; # @c nhận (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 chọn a ($a)\n;
$a;
} else {
print chọn b ($b)\n;
$b;
}
}
Lu ý 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á tầm thờng. 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. Trong thực tế, điều đó cũng đúng đến chỗ cần nói.
Đối
Mặc dầu 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 cho trình con. Trong Perl
nếu lời gọi trình con (với dấu và @ cùng tên 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 biến đầu là mục tiêu
}
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 @_.
Lu ý đặ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); # sẽcho hello, world!
$x = somebody;
&say_hello_to ($x); # cho hello, somebody!
&say_hello_to (me) + &say_hello_to (you) # và me và you
Lu ý rằng trong dòng cuối, giá trị cho lại không thực sự đợc dùng. Nhng 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, lần nữa
&say (goodbye, cruel world) # im lặng
Các tham biến vợt quá đều bị bỏ qua - nếu bạn cha bao giờ nhòm ngó tới $_[3],
thì Perl cũng chẳng bận tâm. 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 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 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 đợ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 ; # khởi đầu giá trị cho sum
foreach $_ (@_ ) {
$sum += $_ ; # cộng từng phần tử
}
$sum ; # biểu thức cuối đợc tính: tổng của tất cả các phần tử
}
$a = &add(4,5,6) ; # cộng 4+5+6 = 15, và gán cho $a

print &add(1,2,3,4,5) ; # ina ra 15
print &add(1..5); # cũng in ra 15, vì 1..5 đợc mở rộng
Điều gì xảy ra nếu ta có motọ biến mang tên $sum khi ta gọi &add_list? Chúng ta
đã đánh trúng vào nó. Trong mục tiếp chúng ta sẽ xem cách thức tránh điều này.
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(), 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, nếu bạn thích từ đao to búa lớn). Sau đây lại là hàm cộng đó, lần này
dùng local():
sub add {
local ($sum) ; # làm cho $sum thành biến cục bộ
$sum = 0 ; # khởi đầu giá trị cho sum
foreach $_ (@_ ) {
$sum += $_ ; # cộng từng phần tử
}
$sum ; # biểu thức cuối đợc tính: tổng của tất cả các phần tử
}
Khi câu lệnh thân đầu tiên đợc thực hiện, 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 trình con này đi ra, thì Perl bỏ qua biến cục bộ và khôi phục giá trị
trớc (toàn cục). Đ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, vân vân). 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ử hơn 100 của một mảng
lớn:
sub bigger_than_100 {
local ($result) ; # tạm thời giữ giá trị trở về

foreach $_ (@_ ) { # đi qua danh sách đối

Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay
×