我知道'can'方法检查包是否有'some_method'方法。但是,“->(animal => $x)”部分发生了什么?
$z = __PACKAGE__->can("some_method")->(animal => $x)
dauxcl2d1#
can()将返回对方法的引用(如果它存在),然后方法将被“取消引用箭头”取消引用。你必须把它 Package 到eval中,否则如果“some_method”不存在,就会出现异常。阅读更多内容:关于can():perldoc UNIVERSAL关于子程序的取消引用:perldoc perlref
can()
perldoc UNIVERSAL
perldoc perlref
bd1hkmkf2#
can返回方法的代码引用。Perl“方法”只是普通的Perl子例程,它期望类或对象(“invocant”)作为第一个参数。
can
sub some_method { my($self, @args) = @_; ... }
在箭头符号中,调用方在左边,方法在右边:
$object->method();
这实际上是调用调用者包中的子例程,其中调用者成为第一个参数:
SomePackage::method($object)
记住,一个对象仅仅是一个受祝福的引用,这意味着该引用已经被标记了一个包名。我们称之为“对象”,当你调用一个对象上的方法时,它使用这个标签来确定从哪里开始寻找要使用的正确子例程。不过,这样直接调用它忽略了几个面向对象的特性。例如,您不会使用继承。您直接调用特定的子例程,而不是让Perl找到适当的方法。回到你的代码。can可以搜索整个继承树,以找到要调用的子例程。它可能不在你开始使用的包中。然后,它返回找到的任何内容的代码引用,但您不知道哪个包提供了该子例程。你也不知道是谁要求的代码引用。您现在有了代码引用,并且希望调用它。你必须自己提供请求者:
$coderef->(INVOCANT, @args);
有人认为“animal”(一个简单的字符串,这意味着这可能是一个类方法)是正确的调用者。此代码的第一个参数不是对象:
$coderef->('animal', @args);
但是,不要使用这样的代码。几乎没有人这样做,它颠覆了面向对象代码的许多优点。我倾向于这样写:
if (eval { __PACKAGE__->can('some_method')}) { __PACKAGE__->some_method(@args); }
请注意,在这里使用__PACKAGE__也很奇怪(这来自于一个习惯性的滥用者)。我怀疑如果你使用它,有一个更好的方法来完成任务。
__PACKAGE__
2条答案
按热度按时间dauxcl2d1#
can()
将返回对方法的引用(如果它存在),然后方法将被“取消引用箭头”取消引用。你必须把它 Package 到eval中,否则如果“some_method”不存在,就会出现异常。阅读更多内容:关于
can()
:perldoc UNIVERSAL
关于子程序的取消引用:
perldoc perlref
bd1hkmkf2#
can
返回方法的代码引用。Perl“方法”只是普通的Perl子例程,它期望类或对象(“invocant”)作为第一个参数。在箭头符号中,调用方在左边,方法在右边:
这实际上是调用调用者包中的子例程,其中调用者成为第一个参数:
记住,一个对象仅仅是一个受祝福的引用,这意味着该引用已经被标记了一个包名。我们称之为“对象”,当你调用一个对象上的方法时,它使用这个标签来确定从哪里开始寻找要使用的正确子例程。
不过,这样直接调用它忽略了几个面向对象的特性。例如,您不会使用继承。您直接调用特定的子例程,而不是让Perl找到适当的方法。
回到你的代码。
can
可以搜索整个继承树,以找到要调用的子例程。它可能不在你开始使用的包中。然后,它返回找到的任何内容的代码引用,但您不知道哪个包提供了该子例程。你也不知道是谁要求的代码引用。您现在有了代码引用,并且希望调用它。你必须自己提供请求者:
有人认为“animal”(一个简单的字符串,这意味着这可能是一个类方法)是正确的调用者。此代码的第一个参数不是对象:
但是,不要使用这样的代码。几乎没有人这样做,它颠覆了面向对象代码的许多优点。我倾向于这样写:
请注意,在这里使用
__PACKAGE__
也很奇怪(这来自于一个习惯性的滥用者)。我怀疑如果你使用它,有一个更好的方法来完成任务。