1. Trang chủ
  2. » Công Nghệ Thông Tin

Hàm

7 115 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Nội dung

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 if ($_ > 100) { # có đủ t cách không? push (@result, $_) ; # cộng nó } $result ; # cho lại danh sách cuối } Đ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. Nhng đ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 { local ($n, @values) ; # tạo ra các biến cục bộ nào đó ($n, @values) = @_ ; # chặt arg thành giới hạn và giá trị local (@result) ; # tạm thời giữ giá trị trả lại foreach $_ (@values) { # đi qua danh sách đối arg if ($_ > $n) { # có đủ t cách không? push (@result, $_) ; # cộng nó } $result ; # cho lại danh sách cuối } # một số lời gọi @new = &bigger_than (100, @list); # @new nhận tất cả @list > 100 @this = &bigger_than(5,1,5,15,30); # @this nhận (15,30) L ý rằng lần này tôi đã dùng hai biến cục bộ phụ để đặt tên cho các đối. Điều này khá thông dụng trong thực hành - dễ nói về $n và @values hơn nói về $_[0] và @_[1 $#_] nhiều lắm. Kết quả của local() là một danh sách gán đợc, nghĩa là nó có thể đợc dùng ở vế bên trái của toán tử gán mảng. Danh sách này có thể đợc đặt giá trị khởi đầu cho từng biến mới đợc tạo ra. (Nếu bạn không đặt giá trị cho danh sách này, thì các biến mới bắt đầu với một giá trị của undef, giống nh bất kì biến mới nào khác.) Điều này có nghĩa là chúng ta có thể tổ hợp hai câu lệnh đầu của trình con này, bằng cách thay thế: local ($n, @values) ; ($n, @values) = @_ ; # chặt arg thành giới hạn và giá trị bằng local ($n, @values) = @_ ; Trong thực tế, đây là một thứ rất đặc thù thông dụng Perl cũng hệt nhu khai báo vậy, local() thực sự là một toán tử thực hiện đợc. Nếu bạn đặt nó vào bên trong chu trình, thì bạn sẽ thu đợc một biến mới cho mỗi lần lặp chu trình, mà gần nh là vô dụng trừ phi bạn thích lãng phí bộ nhớ và quên mất mình đã tính gì trong lần lặp trớc. Chiến lợc lập trình Perl tốt gợi ý rằng bạn nên nhóm tất cả các toán tử local() của mình vào phần đầu định nghĩa trình con, trớc khi bạn chui vào phần thịt của trình này. Bài tập 1. Hãy viết một trình con nhận một giá trị số từ 1 tới 9 và cho lại tên tiếng Anh (nh một, hai, hay chín). Nếu giá trị đa vào ở ngoài phạm vi này, thì hãy cho lại số ban đầu tahy vì cho tên. Hãy thử nó với một số dữ liệu vào - có lẽ bạn sẽ phải viết ra một loại khiển trình nào đó. 1. Hãy lấy chơng trình trong bài tập trớc, viết một chơng trình nhận hai số và cộng chúng lại, hiển thị kết quả kiểu hai cộng hai là bốn. (Chớ quên viết hoa từ đầu!) 1. Hãy mở rộng trình con này để cho lại âm chín qua âm một và không. Hãy thử ch- ơng trình này. . 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. 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,

Ngày đăng: 28/09/2013, 10:20

Xem thêm

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w