2010-07-30 33 views
6

tôi thấy những người sử dụng hai phong cách cho đi qua tên tham số trong Perl:Các thông số thông qua phong cách trong Perl

use strict; 
use warnings; 
use Data::Dumper; 

sub foo { 
    print Dumper @_; 
} 

sub bar { 
    print Dumper @_; 
} 

foo(A => 'a', B => 'b'); 
bar({ A => 'a', B => 'b' }); 

những lợi thế trong việc sử dụng foo() phong cách thay vì bar() phong cách là gì?

Trả lời

9

Phương pháp thứ hai chuyển tham chiếu đến hàm băm, trong khi phương thức thứ nhất chỉ chuyển một danh sách.

Có hai khía cạnh ở đây: về lý thuyết, tham chiếu đến hàm băm có thể tốt hơn về hiệu suất, mặc dù các danh sách đối số ngắn không đáng kể. Đối với một cuộc gọi đơn giản như foo(a => 1, b => 2) không có sự khác biệt về hiệu suất, bởi vì @_ thực sự là bí danh đối với các giá trị ban đầu.

Nhưng nếu người gọi đã có giá trị trong băm, kiểu đầu tiên yêu cầu chuyển đổi từ băm sang danh sách và sau đó quay trở lại băm, có thể chậm.

Khía cạnh thứ hai là câu hỏi chịu trách nhiệm về việc chuyển đổi thành băm. Phong cách đầu tiên lá nó lên chức năng được gọi là, và nếu điều đó chỉ cần my %args = @_, nó sẽ tạo ra cảnh báo tò mò nếu danh sách đối số là không có chiều dài thậm chí.

Đó là lý do tại sao tôi hơi thích kiểu thứ hai (hoặc tôi sử dụng Perl 6, hỗ trợ các đối số được đặt tên nguyên bản).

+1

+1 để chỉ ra các khía cạnh hiệu suất. –

+1

Những "khía cạnh hiệu suất" là tối ưu hóa vi mô không cần thiết mà không mang lại lợi ích thiết thực. Một băm có thể được sử dụng dễ dàng như một danh sách: 'foo (% hash)' hoặc một hashref: 'foo (% {$ hashref})'. Gắn bó với phong cách foo để lại nhiều sức mạnh hơn cho người dùng. – jmz

+0

Trên thực tế, điểm chuẩn của riêng tôi đã được hiển thị (trên nhiều cài đặt) mà nó nhanh hơn để chuyển danh sách so với tham chiếu - mặc dù nó xuất hiện nhanh hơn để tham chiếu * return *. – Axeman

5

Thứ nhất, một lời giải thích trong hai phương pháp:

sub foo { 
    # Transform the array to a hash 
    my %args = @_; 

    foreach my $key (keys %args) { 
     print "$key => $args{$key}\n"; 
    } 
} 

# Pass an array of values 
foo(A=>'a', B=>'b'); 

Trong trường hợp đầu tiên này tất cả các bạn đang làm là đi qua một mảng. => trong ngữ cảnh này không phải là chỉ báo khóa/giá trị băm mà bạn có thể nghĩ. Trong bối cảnh này nó chỉ là một "dấu phẩy chất béo".

sub bar { 
    my ($hash_ref) = @_; 
    foreach my $key (keys %$hash_ref) { 
     print "$key => $hash_ref->{$key}\n"; 
    } 
} 

# pass a ref to an anonymous hash 
bar({ A=>'a', B=>'b' }); 

Trong trường hợp thứ hai này, bạn đang tạo băm ẩn danh và chuyển tham chiếu đến băm đó làm đối số cho hàm.

Tại sao chọn cái này qua cái kia? Trong cuốn sách, Thực hành tốt nhất của Perl, chương 9 dưới tiêu đề "Các đối số được đặt tên", tác giả đề xuất sử dụng kiểu thứ hai khi có nhiều hơn ba đối số cho hàm. Anh ta cũng thích nó hơn vì nó bắt số lượng đối số không khớp vào thời gian biên dịch thay vì ở thời gian chạy.

+3

đó là một lúc kể từ khi tôi đọc nó, nhưng tôi nghĩ rằng khuyến nghị sử dụng một hashref với 3 đối số thay vì danh sách đối số không được đặt tên chuẩn, tức là gọi 'foo (' a ',' b ') ', thay vì giới thiệu hashrefs trên băm – plusplus

+3

@plusplus: Tiêu đề của phần là: "Sử dụng băm của các tranh luận được đặt tên cho bất kỳ chương trình con nào có nhiều hơn ba tranh cãi". Trong phần nội dung của tác phẩm mà anh ta nói cụ thể để sử dụng hàm băm trên các cặp tên/giá trị thô được chuyển đổi thành băm. –

+0

+1 để chỉ định tham chiếu của bạn. –

6

Kiểu foo(a => 1, b => 2) là cách thông thường để mô phỏng đối số được đặt tên. bar({a => 1, b => 2}) thường chỉ được sử dụng cho các đối số bổ sung (và có thể tùy chọn).

Để sử dụng thông thường, tôi thích biểu mẫu đầu tiên. Các {} được đánh máy thêm, thêm tiếng ồn để đọc, và tạo ra một lỗi có thể nếu bạn để lại một hoặc cả hai niềng răng. Bất kỳ sự khác biệt hiệu suất là không đáng kể. (Nếu không, bạn có vấn đề lớn hơn.) Mặt khác, gói các đối số trong một hàm tạo băm vô danh có thể giúp bạn tìm lỗi tại thời gian biên dịch thay vì thời gian chạy.

Biểu mẫu thứ hai thường được kết hợp với các đối số vị trí. ví dụ.Benchmark thực hiện điều này:

cmpthese(10000, { 
    foo => \&foo, 
    bar => \&bar, 
}); 

Trong khi Tk rời {} ra:

my $text = $w->Scrolled('Text', -width => 80, -height => 50); 

Nó thường là một sự lựa chọn phong cách.

Các vấn đề liên quan