Perl需要一点帮助才能实现这个功能,因为它不认为存储在哈希表中的代码引用是“方法”。方法是作为包符号表的条目实现的。Perl比JavaScript更加面向类,而JavaScript则自豪地宣称它更加面向对象(对于单个对象来说)。
为了实现该功能,您需要创建一个将引用映射到此方式的类。绕过符号表中的方法的方法是使用
AUTOLOAD
方法。如果包含
AUTOLOAD
子例程的包在继承链中找不到Perl无法找到的受保护对象时,它将调用
AUTOLOAD
并设置软件包范围的(
our
)变量
$AUTOLOAD
将包含函数的完整名称。
我们通过获取完全限定子名称中最后一个节点(最后一个'::'之后)来获取调用的方法的名称。我们查看该位置是否有代码引用,如果有,我们可以返回它。
package AutoObject;
use strict;
use warnings;
use Carp;
use Params::Util qw<_CODE>;
our $AUTOLOAD;
sub AUTOLOAD {
my $method_name = substr( $AUTOLOAD, index( $AUTOLOAD, '::' ) + 2 );
my ( $self ) = @_;
my $meth = _CODE( $self->{$method_name} );
unless ( $meth ) {
Carp::croak( "object does not support method='$method_name'!" );
}
goto &$meth;
}
1;
然后你会将对象转换为该类:
package main;
my $obj
= bless { foo => 1
, hello => sub { return 'world' }
}, 'AutoObject';
print $obj->hello();
通常,在 AUTOLOAD
子程序中,我会 "固定" 行为。也就是说,我会在包符号表中创建条目,以避免下次使用 AUTOLOAD
。但这通常是针对一个相当明确定义的类行为。
我还设计了一个 QuickClass
,它为每个声明的对象创建一个包,但其中涉及到很多符号表操作,现在可能最好使用 Class::MOP
来完成。
根据 Eric Strom 的建议,您可以将以下代码添加到 AutoObject 包中。每当有人使用 AutoObject
(带参数 'object'
)时,import
子程序都会被调用。
sub object ($) { return bless $_[0], __PACKAGE__; };
sub import {
shift;
return unless $_[0] eq 'object';
use Symbol;
*{ Symbol::qualify_to_reference( 'object', scalar caller()) }
= \&object
;
}
然后,当你想要创建一个“对象字面量”时,你只需要这样做:
use AutoObject qw<object>;
表达式将会是:
object { foo => 1, hello => sub { return 'world' } };
你甚至可以这样做:
object { name => 'World'
, hello => sub { return "Hello, $_[0]->{name}"; }
}->hello()
;
你有一个"对象字面量"表达式。也许更好的称呼这个模块是Object::Literal
。