2011-08-16 34 views
5

Dường như Perl chỉ có thể có các chuỗi làm khóa của băm. (Điều này đã được thay đổi trong một phiên bản nhất định của Perl?) Nó là rất hạn chế để chỉ có thể sử dụng dây như là chìa khóa. Nếu tôi muốn một đối tượng hoặc một mảng là chìa khóa thì sao? Trong Python nó rất dễ sử dụng một mảng, tuple, và các đối tượng khác có thể so sánh, như các khóa dict. Perl không có khả năng so sánh những thứ như mảng cho sự bình đẳng, vì vậy tôi không thấy lý do tại sao chúng không thể được sử dụng làm khóa kiểu ánh xạ.Perl có loại mảng liên kết có thể có bất kỳ loại khóa nào không?

Không có cách nào để sử dụng bất kỳ loại khóa nào trong Perl? Có một mô-đun cung cấp điều này?

Trả lời

3

AFAIK Perl chỉ đơn giản là xâu chuỗi các phím?

package Foo; 

use Moose; 
use overload ('""' => \&stringify); 

sub stringify { 
    return "xxx"; 
} 

package main; 

use v5.10; 
use Data::Dump 'pp'; 

my $foo = Foo->new; 
my $hash = {$foo => 'bar'}; 
say pp($hash); // { xxx => "bar" } 

Bằng cách này bạn cũng có thể sử dụng bất kỳ thứ gì bạn muốn làm khóa băm. Xem thêm điều này thread on Perl Monks.

Đối với sự bình đẳng, hãy xem equality operators in perlop. Toán tử == so sánh số, toán tử eq so sánh theo chuỗi. Điều này có nghĩa là ví dụ: (4, 2) == (1, 2) là đúng (như scalar (4, 2)2), điều này có thể gây bất ngờ cho bạn.

3

Trái ngược với những gì bạn đã nói, Perl KHÔNG có khả năng so sánh những thứ như mảng bình đẳng như bạn yêu cầu. Đối với người mới bắt đầu, Perl không có định nghĩa cho mảng bình đẳng. Và nếu định nghĩa yêu cầu so sánh nội dung của mảng, thì Perl không có định nghĩa bình đẳng cho hầu hết mọi thứ có thể được tìm thấy trong một mảng.

Perl gần nhất có định nghĩa về mảng bình đẳng là địa chỉ của chúng. Nếu đó là những gì bạn muốn sử dụng, sau đó nó là khá dễ dàng:

$key = ['a', 'b']; 
$hash{$key} = [ $key, $val ]; # Prevents the key from being freed. 
print $hash{$key}[1]; 

Nếu không, Perl để bạn thực hiện những gì bạn muốn thay vì buộc bạn phải sử dụng những gì nó cung cấp. Tôi thấy hai cách tiếp cận chính.

Một mã băm được gắn, mã cơ bản trình bày giao diện của một băm mà không thực sự là bảng băm, có thể hỗ trợ bất kỳ loại khóa nào. Bạn có thể sử dụng nó để xác định phiên bản của bạn của mảng bình đẳng. Thậm chí có thể có một mô-đun hiện có (mặc dù tôi không thấy mô-đun nào sau khi tìm kiếm rất nhanh).

Một cách tiếp cận khác là tạo một hàm tạo khóa duy nhất từ ​​biểu thức khóa.

sub key{ "@_" } # Overly simplistic? 
$hash{key('a', 'b')} = $val; 
print $hash{key('a', 'b')}; 
+0

Perl cũng có thể so sánh nội dung của mảng: in 'ok' if (['a', 1 ] ~~ ['a', 1]); –

3

Có, có mô-đun cho điều này trên CPAN: Tie::Hash::StructKeyed. Nó đưa vào tài khoản toàn bộ cấu trúc, nhưng như là một ảnh chụp nhanh. mỗi khóa sẽ trả về tham chiếu gốc.

1

Có, sử dụng dấu kiểm (Hash::Util::FieldHash cho 5.10+ và Hash::Util::FieldHash::Compat cho trước 5.10) để đăng ký băm của bạn dưới dạng fieldhashes và bạn có thể sử dụng bất kỳ tham chiếu nào (và do đó, bất kỳ đối tượng nào) làm khóa cho các băm đó tham chiếu, về cơ bản, và cung cấp logic để xử lý CLONEing qua các chủ đề và thu gom các khóa), ví dụ:

use Hash::Util qw/fieldhashes/; 
fieldhashes \my (%foo, %bar, %baz); 

my %data = (a => 1, b => 2, c => 3); 
my $stuff = {t => 2, u => 3, l => 9}; 
$foo{\%data} = 'x'; 
$foo{$stuff} = 'a'; 
$bar{\%data} = 'y'; 
$bar{$stuff} = 'b'; 
$baz{\%data} = 'z'; 
$baz{$stuff} = 'c'; 


print "$foo{\%data} $bar{\%data} $baz{\%data}\n"; 
print "$foo{$stuff} $bar{$stuff} $baz{$stuff}\n"; 
Các vấn đề liên quan