本文共 10000 字,大约阅读时间需要 33 分钟。
perl子例程
在本系列的中,比较了Perl 5和Perl 6,我们研究了在将代码迁移到Perl 6中可能遇到的一些问题。在 ,我们研究了垃圾收集在Perl 6中的工作方式, ,我们研究了容器如何替换Perl 6中的引用。在第四篇文章中,我们将重点介绍Perl 6中的(子例程)签名以及它们与Perl 5中的区别。
如果要从Perl 5代码迁移到Perl 6,则可能未使用Perl 5.20或任何较早的CPAN模块(例如 , 或任何其他Perl)中可用的 CPAN上的5个模块带有 。
在世界范围内的Perl程序中很少使用(例如 )。由于这些原因,我仅将Perl 6功能与“经典” Perl 5参数传递的最常用用法进行比较。
传递给Perl 5子例程的所有参数将被展平,并放入自动定义的@_
数组变量中。 基本上,Perl 5会将参数传递给子例程。 仅此而已。 但是,Perl 5中有一些习惯用法可以代替它。 根据我的经验,最常见的习惯用法是:
# Perl 5 sub do_something { my ( $foo , $bar ) = @_ ; # actually do something with $foo and $bar }
这个习语对两个(新)词法变量执行列表分配(复制)。 Perl 6也支持这种访问子例程参数的方式,但它只是为了使迁移更容易。
如果期望固定数量的参数后跟可变数量的参数,通常使用以下惯用法:
# Perl 5 sub do_something { my $foo = ; my $bar = ; for ( @_ ) { # do something for each element in @_ } }
这个习语取决于的魔术行为,在这种情况下,该行为从@_
转移。 如果打算将该子例程作为方法调用,则通常会看到类似以下内容:
# Perl 5 sub do_something { my $self = ; # do something with $self }
因为传递的第一个参数是Perl 5中的 。
顺便说一句,这个习语也可以写成第一个习语:
# Perl 5 sub do_something { my ( $foo , $bar , @rest ) = @_ ; for ( @rest ) { # do something for each element in @rest } }
但这会降低效率,因为它将涉及复制可能很长的值列表。
第三个习惯用法是直接访问@_
数组。
# Perl 5 sub sum_two { $_ [ 0 ] + $_ [ 1 ] ; # return the sum of the two parameters }
该习惯用法通常用于小型的单行子例程,因为它是处理参数的最有效方法之一,因为不会进行复制。
如果要更改作为参数传递的任何变量,也可以使用此惯用法。 由于@_
中的元素是任何指定@_
的别名(在Perl 6中,您会说:“绑定到变量”),因此可以更改内容:
# Perl 5 sub make42 { $_ [ 0 ] = 42 ; } my $a = 666 ; make42 ( $a ) ; say $a ; # 42
诸如此类的命名参数在Perl 5中不存在 。但是,有一个常用的成语有效地模仿了命名参数:
# Perl 5 sub do_something { my %named = @_ ; if ( %named { bar } ) { # do stuff if named variable "bar" exists } }
这%named
通过从@_
数组中交替获取键和值来初始化%named
@_
哈希。 如果您使用fat-逗号语法调用带有参数的子例程:
# Perl 5 frobnicate ( bar => 42 ) ;
它将传递两个值"foo"
和42
,这两个值将作为与键"foo"
关联的值42
放入%named
哈希中。 但是,如果您指定以下内容,也会发生相同的事情:
# Perl 5 frobnicate ( "bar" , 42 ) ;
=>
是语法糖,用于自动引用左侧。 否则,它的功能就像逗号一样(因此命名为“胖逗号”)。
如果将子例程作为带有命名参数的方法来调用,则此惯用语将与标准惯用语结合使用:
# Perl 5 sub do_something { my ( $self , %named ) = @_ ; # do something with $self and %named }
或者:
# Perl 5 sub do_something { my $self = ; my %named = @_ ; # do something with $self and %named }
以最简单的形式,Perl 6中的子例程签名非常类似于Perl 5的“标准”惯用语。但是,它们不是该代码的一部分,而是该子例程的定义的一部分,您无需这样做。那作业:
# Perl 6 sub do - something ( $foo , $bar ) { # actually do something with $foo and $bar }
与:
# Perl 5 sub do_something { my ( $foo , $bar ) = @_ ; # actually do something with $foo and $bar }
在Perl 6中, ($foo, $bar)
部分称为子例程的签名 。
由于Perl 6具有实际的method
关键字,因此不必考虑主诉人,因为self
项自动可用:
# Perl 6 class Foo { method do - something - else ( $foo , $bar ) { # do something else with self, $foo and $bar } }
此类参数在Perl 6中称为位置参数 。除非另有说明,否则在调用子例程时必须指定位置参数。
如果需要在Perl 5中直接使用$_[0]
的别名行为,则可以通过指定is rw
特性将参数标记为可写:
# Perl 6 sub make42 ( $foo is rw ) { $foo = 42 ; } my $a = 666 ; make42 ( $a ) ; say $a ; # 42
当您将数组作为参数传递给子例程时,它不会在Perl 6中变平。您只需要在签名中接受一个数组作为数组:
# Perl 6 sub handle - array ( @a ) { # do something with @a } my @foo = "a" .. "z" ; handle - array ( @foo ) ;
您可以传递任意数量的数组:
# Perl 6 sub handle - two - arrays ( @a , @b ) { # do something with @a and @b } my @bar = 1 .. 26 ; handle - two - arrays ( @foo , @bar ) ;
如果您希望Perl 5的( )扁平化语义,可以通过在签名的前面加上星号来用“浆糊数组”来表明这一点:
# Perl 6 sub slurp - an - array ( *@ ) { # do something with @values } slurp - an - array ( "foo" , 42 , "baz" ) ;
稀疏数组只能作为签名中的最后一个位置参数出现。
如果您喜欢使用Perl 5在Perl 6中指定参数的方式,可以通过在签名中指定一个稀疏数组*@_
来实现:
# Perl 6 sub do - like - 5 ( * @_ ) { my ( $foo , $bar ) = @_ ; }
在调用方,Perl 6中的命名参数的表达方式与Perl 5中的表达方式非常相似:
# Perl 5 and Perl 6 frobnicate ( bar => 42 ) ;
但是,在子例程的定义方面,情况非常不同:
# Perl 6 sub frobnicate ( : $bar ) { # do something with $bar }
普通(位置)参数和命名参数之间的区别是冒号,冒号先于 以及定义中的变量名称:
$foo # positional parameter, receives in $foo : $bar # named parameter "bar", receives in $bar
除非另有说明,否则命名参数是可选的 。 如果未指定命名参数,则关联变量将包含默认值,该默认值通常是类型对象Any
。
如果要捕获任何 (其他)命名参数,则可以使用所谓的“稀疏哈希”。 就像slurpy数组一样,它在哈希之前以星号表示:
# Perl 6 sub slurp - nameds ( * %nameds ) { say "Received: " ~ ", " , %nameds ; } slurp - nameds ( foo => 42 , bar => 666 ) ; # Received: bar, foo
与slurpy数组一样,签名中只能有一个slurpy哈希,并且必须在其他任何命名参数之后指定。
通常,您希望将命名参数从具有相同名称的变量传递给子例程。 在Perl 5中,它看起来像: do_something(bar => $bar)
。 在Perl 6中,可以用相同的方式指定它: do-something(bar => $bar)
。 但是,您也可以使用快捷方式: do-something(:$bar)
。 这意味着更少的打字次数和更少的错别字机会。
Perl 5具有以下惯用法,用于使参数成为默认值:
# Perl 5 sub dosomething_with_defaults { my $foo = @_ ? : 42 ; my $bar = @_ ? : 666 ; # actually do something with $foo and $bar }
在Perl 6中,可以通过指定等号和表达式来将默认值指定为签名的一部分:
# Perl 6 sub dosomething - with - defaults ( $foo = 42 , : $bar = 666 ) { # actually do something with $foo and $bar }
如果为位置参数指定了默认值,则它们将变为可选参数。 无论任何默认值,命名参数都保持可选。
Perl 6具有一种描述子例程的参数应如何捕获到该子例程的参数中的方式。 位置参数由其名称和适当的符号(例如$foo
)指示。 命名参数以冒号作为前缀(例如:$bar
)。 可以将位置参数标记为is rw
以允许在调用者的作用域中更改变量。
位置参数可以在一个带有星号(例如*@values
)前缀的稀疏数组中展平。 可以使用粗俗的哈希来收集意外的命名参数,该哈希还以星号作为前缀(例如*%nameds
)。
通过在等号后添加表达式(例如$foo = 42
),可以在签名内指定默认值,这使该参数成为可选参数。
除了此处概述的功能外,Perl 6中的签名还具有许多其他有趣的功能。 如果您想进一步了解它们,请查阅Perl 6 。
翻译自:
perl子例程
转载地址:http://mgjzd.baihongyu.com/