2010-01-27 33 views
5

Làm thế nào tôi sẽ tạo ra một băm như sau:

my %hash = (key1=>"Something", key2=>$hash{key1} . "Else"); 

thể này không được thực hiện trong khi khi tôi tuyên bố băm? Cho đến nay, điều duy nhất tôi đã đưa ra là:

my %hash = (key1=>"Something"); 
$hash{key2} = $hash{key1} . "Else"; 
+2

Tại sao bạn không thể thêm giá trị thứ hai vào giá trị đầu tiên? Vì bạn đang xây dựng băm bạn biết nó. –

+0

Có vấn đề gì với cách bạn nghĩ ra? :) –

Trả lời

11

Tại sao không sử dụng biến trung gian?

my $common_value = 'Something'; 
my %some_hash = (k1 => $common_value, k2 => $common_value.'Else'); 

Cập nhật

kemp hỏi tại sao chúng ta cần một biến trung gian. Tôi có thể giải thích câu hỏi này theo hai cách, tôi sẽ cố gắng trả lời cả hai cách giải thích.

  1. Tại sao bạn không thể làm my %hash = (k1 => 'foo', k2 => $hash{k1}.'bar');?

    Mặt bên phải (rhs) của biểu thức được đánh giá trước bên trái (lhs). Vì vậy, khi giá trị cho k2 được xác định, không có sự đảm bảo nào đối với %hash vẫn chưa xảy ra. Trong thực tế, %hash thậm chí đã không được tạo ra và được nhập vào pad đầu. (%hash là một biến từ vựng ở đây, vì vậy nó sẽ không đi vào bảng biểu tượng.)

  2. Tại sao lại sử dụng biến thay vì phương pháp khác?

    Vâng, có nhiều cách để khởi tạo băm với các giá trị như thế này. Tôi sẽ sử dụng một biến trung gian nếu tôi có một số lượng nhỏ các khóa liên quan để khởi tạo.

    my $cv1 = sub_result() * 5; 
    my $cv2 = "Number: $cv1"; 
    
    my %h = (
        k1 => $cv1, 
        k2 => $cv2, 
        k3 => "Numero: $cv1", 
        k4 => "Big $cv2", 
        k5 => "Round $cv2", 
        k6 => "Whole $cv2", 
        k7 => "-$cv1", 
    ); 
    

    Tuy nhiên, nếu tôi phải xây dựng nhiều giá trị phức tạp phụ thuộc vào nhiều khóa khác nhau, tôi có thể sử dụng cách tiếp cận hướng dữ liệu để khởi tạo băm. Việc thực hiện chính xác sẽ phụ thuộc vào chi tiết tôi không có, nhưng nó có thể trông giống như thế này:

    use Scalar::Util qw(reftype); 
    
    my @init = ( 
        [ key1 => $value     ], 
        [ key2 => \&make_a_value, 'key1' ], 
        [ key3 => \&another_way, 'key2' ], 
    ); 
    
    my %h; 
    for my $spec (@init) { 
        my $key = shift @$spec; 
        my $value = shift @$spec; 
        my @args = @$spec; 
    
        if(reftype $value eq reftype sub {}) { 
         $value = $value->(@h{ @args }); 
        } 
    
        $h{$key} = $value; 
    } 
    

    Đối với trường hợp bất kỳ nơi câu hỏi này arrises, sự lựa chọn như những gì kỹ thuật để sử dụng phụ thuộc vào nhiều chi tiết mà đặc biệt cho trường hợp đó. Vì vậy, chúng tôi còn lại với sự cần thiết để đưa ra tuyên bố chung chung. Các biến trung gian là một cách tốt để tiếp cận vấn đề của OP. Cho dù chúng nên được sử dụng trong trường hợp cụ thể của mình, tôi không thể nói.

+0

Tại sao một biến trung gian cần thiết? –

9

Nó không thể được thực hiện trong 2 lý do:

  1. Đồng thời Perl xử lý key2 => $hash{key1}, nó vẫn chưa liên bộ nhớ được phân bổ với khóa 1 với băm tên băm. Nói cách khác, $hash{key1} không trỏ đến đúng địa điểm trong bộ nhớ cho đến khi sau key2 => $hash{key1} đã được chỉ định.

  2. lý do trước không nêu rõ vấn đề nữa: bạn vẫn chưa đặt %hash vào một bảng biểu tượng của thời gian mà bạn xử lý key2 => $hash{key1} (một lần nữa thứ tự của phân tích/đánh giá), do đó trình biên dịch sẽ barf nếu bạn use strict; như mọi khi. Điều này có thể dễ dàng sửa chữa với tuyên bố my %hash trong tuyên bố trước, nhưng # 1 thì không.

4

Tại thời điểm bạn xác định hàm băm, $ hash {key1} không tồn tại, vì vậy bạn không thể thực hiện điều này trong một câu lệnh. Bạn có thể thực hiện giải pháp của riêng mình và sử dụng khóa phím1 sau khi đã xác định.

1

Có gì sai với

my %hash = (key1 => "Something", key2 => "Something" . "Else"); 

?

Vâng, tôi biết những được giữ chỗ, nhưng bất cứ điều gì họ có thể bạn biết họ tại thời điểm bạn xây dựng băm (hoặc bạn sẽ không xây dựng nó ở tất cả), vậy tại sao bạn không chỉ cần tham gia cùng họ với nhau?

0

Thứ nhất, tôi chỉ làm điều này với giá trị trung gian. Tuy nhiên, bạn có hai tùy chọn nâng cao riêng biệt hơn. Tôi không đề nghị/hoặc/những nếu bạn là người mới để perl - trong thực tế, tôi giống như các giải pháp giá trị trung gian là tốt nhất, nhưng cho đầy đủ:

  • Bạn có thể sử dụng Tie::Hash cho phép bạn thực hiện một đối tượng có thể truy cập với cú pháp băm và dereferencing kiểu băm (->{key1}), bạn có thể tìm thêm thông tin về phương thức này với perldoc perltie và trang người dùng được liên kết ở trên cho Tie::Hash;
  • Bạn có thể từ bỏ ý tưởng sử dụng hàm băm; và, sử dụng một đối tượng, hoặc thậm chí Moose mà sẽ cho phép bạn khởi tạo đối tượng từ một băm, chia sẻ cùng một giá trị. Tôi không thấy nhiều mục đích trong một ví dụ thế giới thực trong việc làm điều này.

Đây là ví dụ về Moose.

package Class; 
use Moose; 
has [qw/key1 key2/] => (isa => 'Str', is => 'rw', init_arg => 'key1'); 

my $o = Class->new({ key1 => 'foobar' }); 
print $o->key1, $o->key2; 
0

Bạn có thể nhận được khá chặt chẽ, nhưng tôi không chắc chắn nó có giá trị khác hơn là mới lạ:

$_->{key2} = $_->{key1} . "Else" for my $hash = { key1 => "Something" }; 
0

Nếu tạo biến trung gian ngoài của% băm là off đặt, sau đó sử dụng một do block có thể làm cho nó thêm thẩm mỹ:

my %hash = (
    do { 
     my $s = 'Something'; 
     (key1 => $s, key2 => $s . 'Else'); 
    }, 
); 

/I3az/

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