2011-09-19 24 views
5

OK. Tôi có một vấn đề cố gắng kế thừa các hằng số được đặt trong một lớp cha cho bất kỳ lớp con nào.Thừa kế các hằng số với gói nội tuyến

#!/usr/bin/perl 
use strict; 
use warnings; 

package Car; 
use Exporter qw(import); 
our @EXPORT_OK = ('WHEELS', 'WINGS'); 

use constant WHEELS => 4; 
use constant WINGS => 0; 

sub new { 
    my ($class, %args) = @_; 
    my $self = { 
     doors => $args{doors}, 
     colour => $args{colour}, 
     wheels => WHEELS, 
     wings => WINGS, 
    }; 
    bless $self, $class; 
    return $self; 
} 

package Car::Sports; 
use base qw(Car); 

sub new { 
    my ($class, %args) = @_; 
    my $self = { 
     doors => $args{doors}, 
     engine => $args{engine}, 
     wheels => WHEELS, 
     wings => WINGS, 
    }; 
    bless $self, $class; 
    return $self; 
} 

package main; 
my $obj = Car->new(doors => 4, colour => "red"); 
print Dumper $obj; 

my $obj2 = Car::Sports->new(doors => 5, engine => "V8"); 

print Dumper $obj2; 
__END__ 

Lỗi này là:

Bareword "WHEELS" not allowed while "strict subs" in use at ./t.pl line 30. 
Bareword "WINGS" not allowed while "strict subs" in use at ./t.pl line 30. 
Execution of ./t.pl aborted due to compilation errors. 

Bây giờ, tôi đã không đến đây để gửi mà không làm một số nghiên cứu. Tôi hiểu rằng một tùy chọn sẽ là use Car qw(WHEELS WINGS) trong Car::Sports. Tuy nhiên, nếu tôi làm như vậy tôi nhận được lỗi sau, bởi vì các lớp đều là nội tuyến trong cùng một tệp:

Can't locate Car.pm in @INC 

Vì nhiều lý do, tôi cần giữ gói của mình trong một tệp. Có cách nào để giái quyết vấn đề này không? Như hằng số về cơ bản chỉ là subs, tại sao tôi phải nhập chúng khi như vậy sẽ không đúng cho một phương pháp bình thường?

Cuối cùng, tôi cũng biết tôi có thể làm điều này:

package Car::Sports; 
use base qw(Car); 

sub new { 
    my ($class, %args) = @_; 
    my $self = { 
     doors => $args{doors}, 
     engine => $args{engine}, 
     wheels => Car::WHEELS, 
     wings => Car::WINGS, 
    }; 
    bless $self, $class; 
    return $self; 
} 

Và nó là tốt ... Nhưng tôi có một số lớp học và muốn làm cho thừa kế của các hằng số chung chung hơn là phải đặt tên cho cha mẹ lớp một cách rõ ràng (và đôi khi nó không chỉ là lớp cha, mà là ông bà).

Rất cám ơn trước cho bất kỳ con trỏ nào!

Cheers

Trả lời

6

Một workaround là để bao gồm các dòng

 
package Car::Sports; 
use base qw(Car); 
Car->import(qw(WHEELS WINGS)); 

sử dụng sigils trong Car::Sports constructor:

... 
wheels => &WHEELS, 
wings => &WINGS, 
... 

lớp Car của bạn không được xác định @EXPORTS_OK của nó danh sách cho đến khi thời gian chạy. Các sigils là bắt buộc vì hàm tạo Car::Sports được phân tích cú pháp tại thời gian biên dịch và trình biên dịch không biết phải có các ký hiệu WHEELSWINGS trong không gian tên Car::Sports.


Cách duy nhất để tránh những sigils là xác định xuất khẩu Car 's tại thời gian biên dịch:

package Car; 
our @EXPORT_OK; 
BEGIN {@EXPORT_OK = qw(WHEELS WINGS)} # set at compile not run time 
... 

package Car::Sports; 
use base qw(Car); 
BEGIN {Car->import('WHEELS','WINGS')} # import before c'tor is parsed 

Bạn cũng có thể tránh được những mưu bằng cách xác định lớp Car ở riêng của mình Car.pm tệp. Sau đó, bạn sẽ chỉ nói

use Car qw(WHEELS WINGS); 

và tất cả mọi thứ trong file Car.pm sẽ được phân tích tại thời gian biên dịch, VÀ Exporter::import phương pháp (kích hoạt bởi một cuộc gọi đến Car::import) sẽ tự động được chạy và nhập khẩu những biểu tượng mong muốn không gian tên hiện tại của bạn .

+0

Hoàn hảo! Bạn đã thực sự giải thích điều này tốt và dạy tôi điều gì đó! – wawawawa

+0

Ngoài ra, làm cho 'Xe :: Thể thao' một phân lớp của' Xe' sẽ cung cấp cho 'Xe :: Thể thao' truy cập vào phương pháp' Xe '*, nhưng không phải * chức năng của nó * như' & WHEELS' và '& WINGS'. Việc gọi 'use base qw (Car)' là thừa cho đến khi bạn thêm một số phương thức vào lớp 'Car'. – mob

3

Thay đổi này có phù hợp với nhu cầu của bạn không?

[...] 
    wheels => $class->SUPER::WHEELS, 
    wings => $class->SUPER::WINGS, 
    [...] 

Sử dụng Data :: Dumper bạn nhận được:

$VAR1 = bless({ 
      'wings' => 0, 
      'colour' => 'red', 
      'doors' => 4, 
      'wheels' => 4 
      }, 'Car'); 
$VAR1 = bless({ 
      'wings' => 0, 
      'engine' => 'V8', 
      'doors' => 5, 
      'wheels' => 4 
      }, 'Car::Sports'); 
+0

Tuyệt vời ... Cảm ơn vì điều này. Tôi đã chơi đùa với 'SUPER', nhưng không sử dụng' $ class'. – wawawawa

3

Alternative, bạn có thể thực hiện chính xác những gì use làm:

BEGIN { 
    package Car; 
    use Exporter qw(import); 
    @EXPORT_OK = qw(WHEELS); 

    ... 

    $INC{'Car.pm'} = 1; 
} 

BEGIN { 
    package Car::Sports; 

    use Car qw(WHEELS); 
    @ISA = 'Car'; 

    ... 

    $INC{'Car/Sports.pm'} = 1; 
} 
+0

ikegami - Tôi nghĩ rằng tôi nhớ bạn từ Perlmonks! Tôi đánh giá cao ý kiến, thankyou! – wawawawa

0

Nói chung, để lộ một cái gì đó là một hằng số đối với bất kỳ gói khác với việc xác định nó thực sự là một ý tưởng tồi. Điều này cho rằng, trong số những thứ khác, chống lại việc sử dụng các hình thức bất thường khi đề cập đến các giá trị xảy ra không đổi trong các khu vực khác của mã của bạn.

Module constant thực sự hỗ trợ một hình thức gọi mà giấu đi sự thật rằng chúng ta đang nói về hằng số, bởi vì như gọi hằng số như các phương pháp lớp học làm việc tốt:

package Car; 
use constant default_wheel_count => 4; 

package Car::Sports; 

sub new { 
    my ($class) = @_; 

    return bless { 
     wheels => $class->default_wheel_count, 
    } => $class; 
} 

Đó là cách người ta thực sự thừa hưởng hằng, nhưng nó vẫn có thể là cách tiếp cận sai lầm. Loại bỏ các copypasta bằng cách chỉ sử dụng các hằng số từ các lớp thực hiện việc xây dựng các thuộc tính đó là điều thực sự đúng.

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