假設我有這個代碼:
#!/usr/bin/perl
use warnings;
use strict;
package Guy;
sub new {
my $type = shift;
my %params = @_;
my $self = {};
$self->{'First'} = $params{'First'};
$self->{'Middle'} = $params{'Middle'};
$self->{'Last'} = $params{'Last'};
bless $self, $type;
}
sub printMe
{
printf "-----------------------------------\n";
printf "My type is: \"$self->{type}\"\n"; # Line 18
printf "First :: $self->{First}\n"; # Line 19
printf "Middle :: $self->{Middle}\n"; # Line 20
printf "Last :: $self->{Last}\n"; # Line 21
printf "-----------------------------------\n";
}
package main;
my $dude = Guy->new( 'First' => "John", 'Middle' => "Jacob", 'Last' => "Smith" );
$dude->printMe();
輸出是:
me@ubuntu1$ ./toy01.perl
Global symbol "$self" requires explicit package name (did you forget to declare "my $self"?) at ./toy01.perl line 18.
Global symbol "$self" requires explicit package name (did you forget to declare "my $self"?) at ./toy01.perl line 19.
Global symbol "$self" requires explicit package name (did you forget to declare "my $self"?) at ./toy01.perl line 20.
Global symbol "$self" requires explicit package name (did you forget to declare "my $self"?) at ./toy01.perl line 21.
Execution of ./toy01.perl aborted due to compilation errors.
me@ubuntu1$
所以這里的問題是類方法printMe()不能訪問存盤在$self哈希中的屬性,哈希是在建構式中填充的。我很困惑為什么。
在建構式中,$self被創建為一個散列,用于存盤傳遞給建構式的屬性。$self當它需要是全域的或類似的東西時,它是用本地范圍創建的嗎?或者我在printMe()方法的頂部缺少一個使$self可見的命令,還是什么?
以及如何參考屬性type,這是在建構式中設定但未存盤在$self哈希中的屬性?(我的$self->{type}電話顯然是拼命嘗試在這里找到解決方案。)
任何建議或反饋都在這里表示感謝,謝謝。
uj5u.com熱心網友回復:
物件作為第一個引數發送到方法,但您需要自己填充變數:
sub printMe
{
my ($self) = @_;
...
注意$self->{type}不存在。使用ref $self或blessed($self)來自Scalar::Util。
此外,使用沒有格式字串的printf是沒有用的。改用print或say,或printf正確使用:
printf "First :: %s\n", $self->{First};
uj5u.com熱心網友回復:
您已經接受了一個很好的“如何解決此問題”的答案。但可能值得更深入地挖掘出問題所在。
您有兩個子例程(它們實際上是方法,但這在 Perl 中基本相同):
sub new {
...;
my $self = {};
# code populating $self
...;
bless $self, $type;
}
和:
sub printMe {
# code accessing $self
}
在里面new()你$self用my. 這絕對是正確的做法,但其效果my是創建一個“詞法”變數——該變數僅在您宣告它的代碼塊內可見(即在new()子例程內)。
然后,當您嘗試訪問子例程$self內部printMe()時,您會收到警告 - 因為該變數根本不存在于該子例程中。但顯然,您需要訪問printMe(). 那么這是如何作業的呢?
嗯,Perl 附帶了很多檔案。perlobj手冊頁解釋了內置物件系統是如何作業的。
關于建構式的部分有一個撰寫new()方法的示例。這和你的很相似。關鍵的代碼行是這一行:
return $self;
這表明構造方法需要回傳你的祝福物件。建構式中的等效行是這樣的:
bless $self, $type;
你做事的方式略有不同,但沒關系。這一切都按預期作業。這是方法的最后一行,Perl 子例程將回傳最后一個運算式求值的結果。所以這和寫作一樣(稍微明確一點):
return bless $self, $type;
好的,所以您已經從建構式回傳了物件,并且將該物件存盤在$dude變數中:
my $dude = Guy->new(...);
現在我們需要將該物件重新放入printMe()方法中,以便您可以使用它。perlobj 手冊頁有一個關于方法呼叫的部分,其中包括:
在物件上呼叫方法寫為
$object->method.
和:
當你呼叫一個方法時,箭頭左邊的東西作為第一個引數傳遞給方法。
如果您閱讀名為A Method is Simply a Subroutine的部分,您會看到:
一個方法的特別之處在于它期望接收一個物件或一個類名作為它的第一個引數。
還有一個示例方法:
sub save {
my $self = shift;
open my $fh, '>', $self->path() or die $!;
print {$fh} $self->data() or die $!;
close $fh or die $!;
}
看!還有一個$self變數。我們將物件傳遞給子例程(隱式地,通過使用$object->method()語法)并將物件存盤在一個名為的新變數中,該變數$self也被宣告為my,因此也只能在子例程中使用。
回顧您的代碼,您正確地呼叫了該方法:
$dude->printMe();
唯一的問題是您沒有$self在方法中設定變數printMe()。所以要解決這個問題,您只需將此行添加到方法的開頭:
my $self = shift;
抱歉...持續的時間比我預期的要長。希望它有用。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/530933.html
標籤:perl目的范围属性
上一篇:Perl:復制UDP資料包
