使用 Perl 的 Method::Signatures,为什么我不能在对象实例上调用方法?

Using Perl's Method::Signatures, why can't I invoke methods on an object instance?

我关注了.

现在,当我尝试调用方法 testScript 时,出现错误 global symbol $obj requires explicit package name,并且无法调用 testScriptTwo

use strict;
use warnings;

package Test;

use Method::Signatures;

method new {
    my $obj = bless {}, $self;
    return $obj;
}

method testScript {
       $obj->testScriptTwo(); # Error happens here
}

method testScriptTwo { ... }

测试脚本:

use Test;

my $class = Test->new();
$class->testScript();

如何使用 $obj 调用包本身内的方法?

改用这个:

method testScript {
       $self->testScriptTwo();
}

第一个参数在变量 $self 中,而不是 $obj

您的问题似乎表明您不了解作用域的基础知识以及普通 Perl 对象的工作原理。

在 Perl 中,当您在包名称或 blessed 引用上使用 ->method 语法时,将调用该包中的子例程 method。子例程的第一个参数是您调用 method.

的对象

所以,如果你这样做

My::Friend->new('Alfred');

My::Friend 中的 new 子例程接收两个参数。 My::FriendAlfred.

在新方法中,习惯上将第一个参数称为$class,但这完全取决于您。如果您愿意,可以使用 $basket_case

sub new {
   my $basket_case = shift;
   my $basket = shift;
   my $obj = bless { name => $basket } => $basket_case;
   return $obj;
}

如果您随后对返回的引用调用方法,该方法将接收所述引用作为其第一个参数,从而允许您访问存储在该引用中的数据:

sub blurb {
    my $schmorp = shift;
    print $schmorp->{name}, "\n";
    return;
}

综合起来:

#!/usr/bin/env perl

package My::Package;

use strict;
use warnings;

sub new {
    my $basket_case = shift;
    my $basket = shift;
    my $obj = bless { name => $basket } => $basket_case;
    return $obj;
}

sub blurb {
    my $schmorp = shift;
    print $schmorp->{name}, "\n";
    return;
}

sub derp {
    my $herp = shift;
    printf "%s derp derp\n", $herp->{name};
    return;
}

package main;

my $x = My::Package->new('Alfred');

$x->blurb;
$x->derp;

输出:

Alfred
Alfred derp derp

您需要了解这些基础知识。在理解下面的内容之前,试图在基础之上再增加一层抽象不会让事情变得更容易。

现在,如果您使用 Method::Signatures,按照惯例,它会将隐含的第一个参数放入 lexically scoped 变量中,默认情况下,它调用 $self.

您可以在特定方法中覆盖该名称,在 new 中这样做可能是一个好主意,以传达它不期望对象实例的事实;取而代之的是 returns 一个新实例。

无论您在一个子程序中如何称呼该词法范围的实例变量,都不会影响它在另一个子程序中的名称。例如:

#!/usr/bin/env perl

use strict;
use warnings;

sub a_number {
    my $number = int(rand(10));
    return $number;
}

sub square_that_number {
    my $x = shift;
    return $x * $x;
}

my $bzzzt = a_number();
my $trrrp = square_that_number($bzzzt);

print $trrrp, "\n";

输出:

$ ./zt.pl
36

好的,你需要回溯一下 - 你 new 方法首先被破坏了,这表明你并不真正理解 OO perl 是怎么回事。

一个非常简单的对象如下所示:

package Foo;

sub new {
    #when Foo -> new is called, then 'Foo' is passed in as the class name
    my ( $class ) = @_;
    #create an empty hash reference - can be anything, but $self is the convention
    my $self = {};
    #tell perl that $self is a 'Foo' object 
    bless ( $self, $class );
    #return the reference to your `Foo` object
    return $self;  
}

sub set_name {
   my ( $self, $new_name ) = @_;
   $self -> {name} = $new_name;
}

sub get_name {
   my ( $self ) = @_;
   return $self -> {name}; 
}

当您在代码中调用它时:

use Foo;

my $new_instance = Foo -> new();

class 被传递到 new 方法,然后您使用 bless 创建实例化对象。

然后你可以用它 'do stuff' - 当你 'call' 使用 -> 的方法时,子例程中的 first 参数是对象引用。

所以

$new_instance -> set_name ( "myname" ); 
print $new_instance -> get_name();

相当于:

Foo::set_name($new_instance, "myname" );
print Foo::get_name($new_instance);

你对 $new_instance 采取行动,这是一种允许你包含代码的魔法散列。

在您了解 OO 的基础知识之前,

Method::Signatures 在很大程度上是无关紧要的。但是 that 所做的是 'simply' 扩展模块中的功能,这样你就不必提取 self/class 等

默认情况下,定义为 method 的方法会自动提供 $self没有 $obj 就像你用的一样。这是您 new 方法的本地变量,在该方法之外根本不存在。