如果我将其作为参数传递,我会收到错误:
'找不到对象方法" getline"通过包"坏"在Bad.pm第27行。'
但是如果我将它插入模块就可以了。 这是简化的代码。 bad.pl使用Bad.pm模块。设置$ CAUSE_ERROR以查看问题。
#!/usr/bin/env perl
# This is bad.pl
use strict;
use warnings;
use IO::File;
use Bad; # use the bad module "Bad.pm"
&Main();
sub Main {
my $filename = "bad.pl";
warn "About to parse '$filename'\n";
my $MyWord = Bad->new(); # Create a new object.
my $io = IO::File->new($filename, "r");
#####################
my $CAUSE_ERROR = 1; # Set to 0 it does NOT cause an error. Set to 1 it DOES.
#####################
if($CAUSE_ERROR ) {
$MyWord->Parse($MyWord, $io);
} else {
$MyWord->{fd} = $io;
$MyWord->Parse($MyWord);
}
}
这是Bad.pm
package Bad;
# This is Bad.pm
use warnings;
use strict;
sub new {
my ($class, $args) = @_;
my $self = {
fd => undef,
};
return bless($self, $class); # Changes a function to a class
}
sub Parse {
my ($MyWord, $io) = @_;
if(defined($MyWord->{fd})){
# WORKS
$io = $MyWord->{fd};
while ( defined(my $inputline = $io->getline) ) {
print "${inputline}";
}
} else {
# FAILS
while ( defined(my $inputline = $io->getline) ) {
print "${inputline}";
}
}
}
1;
在Cygwin下使用Perl v5.22.3。 最初我在子目录中有Bad.pm,但我简化了它。 谢谢你的时间。
答案 0 :(得分:0)
总结发布代码中的错误:类名被传递给幕后的构造函数,方法的对象也是如此;我们不供应它们。我们确实将文件句柄传递给new
,以便将其分配给对象的数据,因此可以由类中的方法使用。
这是一个基本的例子。我尽可能地坚持发布的设计。这对I / O对象所需要的内容并不多,而是通常编写类。
该类用于处理文件,已为其传递文件句柄。我们希望每个对象有一个文件句柄。由于我们打开它,关闭它的责任留给了来电者。
<强> script.pl 强>
use strict;
use warnings;
use feature 'say';
use IO::File;
use ProcessFile;
my $filename = shift || $0; # from command line, or this file
say "About to parse '$filename'";
my $io = IO::File->new($filename, "r") or die "Can't open $filename: $!";
my $word = ProcessFile->new($io); # Create a new object, initialize with $io
$word->parse();
# OR, by chaining calls
#my $word = ProcessFile->new($io)->parse();
say "Have ", ProcessFile->num_objects(), " open filehandles";
$io->close;
包文件 ProcessFile.pm
package ProcessFile;
use warnings;
use strict;
use Carp qw(croak);
use Scalar::Util qw(openhandle);
# Example of "Class" data and methods: how many objects (open filehandles)
our $NumObjects;
sub num_objects { return $NumObjects }
sub DESTROY { --$NumObjects }
sub new {
my ($class, $fh) = @_; # class name, arguments passed to constructor
# To also check the mode (must be opened for reading) use Fcntl module
croak "No filehandle or not open or invalid " if not openhandle $fh;
my $self = { _fh => $fh }; # add other data that may make sense
bless $self, $class; # now $self is an object of class ProcessFile
++$NumObjects;
return $self;
}
sub parse {
my ($self, @args) = @_; # object, arguments passed to method (if any)
# Filehandle is retrieved from data, $self->{_fh}
while ( defined(my $inputline = $self->{_fh}->getline) ) {
print $inputline;
}
# Rewind before returning $self (or not, depending on design/@args)
# Can do more here, set some data etc, as needed by class design
seek $self->{_fh}, 0, 0;
return $self;
}
1;
关于上述代码的一些评论如下。让我知道是否会有更多帮助。
类数据和方法不属于任何一个对象,并且用于与整个类相关的目的(例如,跟踪播放中的所有对象)。
DESTROY
方法在对象被销毁时运行,例如当它超出范围时。在这里我们需要它以减少现有对象的数量。尝试:将代码创建一个对象放在一个块{ ... };
中,看看我们在块后得到的数量。
我们使用Scalar::Util中的openhandle
来测试文件句柄是否已打开。我们还应该测试它是否对阅读是开放的,因为这是该类的固定目的,使用Fcntl。
在唯一的示例方法parse
中,我们读出文件,然后在返回对象之前回退文件句柄。这是一个占位符,用于保存和/或设置重复使用的状态。所做的工作取决于课程的目的和设计,并可以通过参数进行控制。
文档:教程perlootut和参考perlobj关于Perl中面向对象的工作,perlmod关于模块(类首先是包)和教程perlreftut供参考。
周围也有很多信息性的SO帖子,请搜索。
答案 1 :(得分:0)
总结:
$MyWord->Parse($MyWord, $io);
鉴于$MyWord
是Bad
类中的一个引用(即,它是Bad
的实例),这将使用参数{{1}调用Bad::Parse
}。也就是说,它的行为就像你打电话:
($MyWord, $MyWord, $io)
但是,Bad::Parse($MyWord, $MyWord, $io)`.
编写为期望参数Bad::Parse()
,因此($MyWord, $io)
设置为第二个$io
,而$MyWord
会引发错误尝试调用Bad::Parse()
,因为$io->getline
模块没有实现该方法。
修复很简单:
将该功能称为Bad
。
将$MyWord->Parse($io)
中第一个参数的变量名称从Bad::Parse()
更改为$MyWord
。这不是严格的必要 - 你可以在技术上调用这个变量 - 但它是常规的,并且会使你的代码对其他Perl程序员更具可读性。