Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何编写一个既作为普通子例程又作为类方法工作的Perl子例程?_Perl - Fatal编程技术网

如何编写一个既作为普通子例程又作为类方法工作的Perl子例程?

如何编写一个既作为普通子例程又作为类方法工作的Perl子例程?,perl,Perl,我正在写一个本质上基本上是静态的函数。我想将其插入模板工具包,该工具包将传递类名。从本质上讲,它正在做 ClassName->function( $args.. ) 但我希望它能像这样 ClassName::function( $args.. ) 里面 sub function { } 处理这两种情况的正确方法是什么?通常没有。sub要么编写为作为方法调用,要么不是 请参阅如何通过在参数列表前加上包名来处理这种情况 现在,在非常具体、有限的情况下,您可以执行以下操作: shift i

我正在写一个本质上基本上是静态的函数。我想将其插入模板工具包,该工具包将传递类名。从本质上讲,它正在做

ClassName->function( $args.. )
但我希望它能像这样

ClassName::function( $args.. )
里面

sub function {
}

处理这两种情况的正确方法是什么?

通常没有。
sub
要么编写为作为方法调用,要么不是

请参阅如何通过在参数列表前加上包名来处理这种情况

现在,在非常具体、有限的情况下,您可以执行以下操作:

shift if $_[0] eq __PACKAGE__;

sub
被作为类方法调用时,作为sub中第一行放弃第一个参数。

模板工具包期望它的插件使用OO,因此无法提供该接口。如果你还想要一个功能界面,你有两个选择

Perl并没有真正区分函数和方法。主要区别在于,方法调用语法隐式包含对象引用(或类名,取决于调用方式)作为第一个参数。您可以使用函数调用语法并手动提供引用对象:

ClassName::function('ClassName', @args);
但那太乱了。更清洁的解决方案是将其分成两个子系统,其中一个子系统为另一个子系统提供包装。e、 g

package ClassName;

sub function {
    # do something
}

sub method {
    my $class = shift;
    function(@_);
}

该函数也可以是该方法的包装器。正如Sinan所提到的,File::Spec通过创建两个模块来实现这一点:一个模块具有OO接口,另一个模块具有功能接口。

这里是一个更安全的版本,它结合并回答了以下问题:

  • 处理从派生对象调用方法的可能性
  • 不会将
    ClassName::function(“ClassName”)
    误解为方法调用
守则:

if (@_ == $nArgsExpectedForThisFunc + 1) {
    $_[0] eq __PACKAGE__ || UNIVERSAL::isa($_[0], __PACKAGE__) || die;
    shift;
}

这要求您知道预期的参数数量;如果没有,但可以将第一个参数与作为方法调用时可能发送的允许值区分开来(例如,如果第一个参数必须是arrayref),则仍然可以应用相同的一般原则。

+1。如果您的每个函数都采用固定数量的参数,那么这将变得更安全,在这种情况下,您可以根据是否比预期多1个参数来决定是否使用了OO调用语法。(目前,调用“ClassName::function('ClassName');”将触发误报。)或者让Perl为您包装:“package ClassName::Functional;sub AUTOLOAD{no strict refs;ClassName->$AUTOLOAD(@)}”@j_random_hacker:没有严格的refs就不应该是严格的“refs”或者它在strict subs:)下失败,除非它不需要,因为在strict refs下允许使用->$method。$AUTOLOAD是完全限定的,所以您需要我们的$AUTOLOAD=~s/*:/;或者你得到无限递归。@ysth:谢谢!(这么少的代码中有这么多的bug,哇…)你知道为什么在没有严格的“refs”的情况下允许“->$method”吗?仅仅是另一个任意的Perl不一致性?严格的引用是为了防止人们意外地使用符号引用;如果$method没有包,那么它就不是任何类型的引用,如果它确实有包,那么它显然是有意的。goto&$funcref也被豁免了。+1很好的组合,但我也喜欢Michael Carman的包装器思想:为什么要做类似ClassName::function($args..)的事情?它是一个静态/辅助方法,并不真正依赖于类?