Perl6:函数/子例程的变元数目

我希望能够在Perl6中运行具有可变数量参数的函数,但是在通读https://docs.perl6.org/language/functions#Arguments后,我看不到如何完成此工作。我看到许多其他语言的链接,并警告说“标题频繁的问题经常被否决”,但我在文档或StackOverflow的任何地方都看不到它。

我想做这样的事情:

some-test($v1, $v2)

要么

some-test($v3)

但没有multi为每个使用单独的功能

我该如何构造一个Perl6子例程来接受可变数目的字符串?

雷夫

TL; DR您正在询问可变参数功能。1简单使用很简单。P6的某些功能(最引人注目的是位置和命名参数)以及可变参数解构会增加一些皱纹。另外,请参阅其他答案,它们也非常有帮助。

可变数量的参数

简单使用简单的可变参数函数:

sub variadic (|args) { say args .elems }
variadic();           # 0
variadic('1');        # 1
variadic('1', '2');   # 2

|foo参数吸食了所有剩余的参数成Capture结合到sigilless标识符foo

sub variadic ($a, @b, %c, |others) { say others[0] }
variadic 1, [2,3], (:foo), 4, [5,6], (:bar); # 4

在上面的示例中,others参数“ slurps” 1以列出的最后三个自变量开始,以4

可变参数的变化

事情并不总是那么简单:

variadic(1, 2);       # 2 -- works but args are Ints
variadic(:foo,:bar);  # 0 -- where did :foo, :bar go?
variadic((:foo));     # 1 -- works; arg is Pair (:foo)
variadic((1, 2));     # 1 -- works; arg is List (1,2)

在此答案的其余部分中,我将解释:

  • 约束参数,例如确保它们都是字符串。

  • 位置命名参数;**@foo*%foo

  • 可变位置分解;+@foo*@foo

约束参数

可变数量的字符串

您可以使用where子句将任何想要的约束强加于限定参数subset如果需要,您可以依次将其打包为一个。)

例如,将所有参数约束为type Str

sub variadic (|args where .all ~~ Str) { say args .elems }
variadic();         # 0
variadic('1');      # 1
variadic('1', '2'); # 2
variadic(1);        # Constraint type check failed

位置命名参数;**@foo*%foo

P6支持位置参数命名参数

|foo在签名中使用总是捕获所有剩余的参数,包括位置参数和命名参数:

sub slurps-into-WHAT (|args) { say WHAT args }
slurps-into-WHAT(); # (Capture)

Capture存储位置参数在一个内部列表,经由位置的下标(即,可访问args[...]通过缔下标访问)和命名的参数中的散列(即,args<...>args{...}):

sub variadic (|args) { say " {args[1]} {args<named2>}" }
variadic('pos0', 'pos1', named1 => 42, named2 => 99); # pos1 99

有时,最好只收集命名的args,或者只收集位置的args,或者收集两个args,但使用单独的参数。

要收集命名参数,请使用以下形式的参数*%foo(一个星号前缀和一个哈希参数):

sub variadic-for-nameds (*%nameds) { say %nameds }
variadic-for-nameds(:foo, :bar); # {bar => True, foo => True}

(请注意,所有方法都以这种方式收集已命名的args,即使它们的签名未明确说明也是如此。2

要收集位置参数,请使用以下形式的参数**@foo(两个星号前缀,后跟一个数组arg):

sub variadic-for-positionals (**@positionals) { say @positionals }
variadic-for-positionals(1, 2, 3); # [1 2 3]

可变位置分解;+@foo*@foo

P6提供了一系列非可变参数解构特征

第一个可变参数位置分解参数形式为+@foo**@foo除了在一种情况下,这具有完全相同的效果如果可变参数仅获得一个参数,并且该参数是列表或数组,则该参数将绑定到该列表或数组的内容,从而删除列表/数组容器:

sub variadic-plus (+@positionals) { say @positionals }
variadic-plus(1,2,3);   # says same as for **@positionals
variadic-plus(1);       # says same as for **@positionals
variadic-plus([1]);     # [1]     -- instead of [[1]]
variadic-plus((1,2,3)); # [1 2 3] -- instead of [(1 2 3)]

+@foo引入表格以支持“单个arg规则”由核心开发人员编写内置插件使用。用户可能希望在想要相同的行为时使用它。

另一个可变参数位置破坏形式为*@foo它与+@foo从列表或数组容器args中提取内容并将容器扔掉的功能相同。但这要更具侵略性:

  • 它针对所有参数执行此操作。

  • 如果参数是列表而不是数组((...)而不是[...]),则它会下降到该列表中,并且如果列表的元素本身是另一个内部列表或数组,则递归重复该练习。

从而:

sub variadic-star (*@positionals) { say @positionals }
variadic-star((1,2),[3,4]);             # [1 2 3 4]
variadic-star((1,2),(3,4,(5,6,(7,8)))); # [1 2 3 4 5 6 7 8]
variadic-star((1,2),(3,4,[5,6,(7,8)])); # [1 2 3 4 5 6 (7 8)]

(请注意,它是如何从[5,6,(7,8)]数组中删除容器,但没有降入数组。)

最后一件事;是否有可变的命名解构参数?你告诉我。3

奖励部分:foo(...)vsfoo (...)

(我将这个奖金部分包括进来,希望它能避免造成混乱。如果此部分本身令人困惑,请忽略它。)

例行调用可以在其参数列表的周围带有或不带有括号的形式编写,它们表示相同的意思。开头的括号必须立即遵循例程名称,且不得插入空格:

sub foo  (|args)  { say args[0] }
foo 'a', 'b';    # a
foo('a', 'b');   # a

(此规则仅适用于日常通话,程序名称及其之间的争论,它并不适用于常规申报,程序名称和它之间的参数。对于后者,声明,你可以不留下任何空间或利用空间就像我上面提到的一样,sub foo (|args)没有区别。)

如果您foo在通话中和括号之间插入空格,您将写出不同的内容:

foo  ('a', 'b'); # (a b)

foo一个参数调用,一个列表('a', 'b')与此相反foo('a', 'b')foo两个参数调用括号内的两个值。

以下foo带有两个参数的调用两个参数都是列表:

foo ('a', 'b', 'c'),  ('d', 'e', 'f'); # (a b c)

您可以嵌套括号:

foo(  ('a', 'b', 'c'),  ('d', 'e', 'f')  )    ; # (a b c)
foo  (('a', 'b', 'c'),  ('d', 'e', 'f'))      ; # ((a b c) (d e f))
foo( (('a', 'b', 'c'),  ('d', 'e', 'f')) )    ; # ((a b c) (d e f))

后两个foo调用获得一个参数,即一个列表( ('a', 'b', 'c'), ('d', 'e', 'f') )(恰好包含两个内部列表)。

脚注

1对此的标准行业术语是可变参数功能在撰写此答案时,Rakudo P6编译器在错误消息中使用了行业标准术语(“可变”),但是官方的P6文档倾向于使用单词“ slurpy”而不是“ variadic”,并谈论“混淆参数” ”。

2方法始终具有一个隐式可变参数命名参数,%_如果未明确指定该参数则调用

say .signature given my method foo {} # (Mu: *%_)

3 P6语言和/或Rakudo P6编译器当前允许以+%foo形式编写参数**%foo杂乱无章的名字进行销毁确实没有任何意义。也许这解释了为什么这两种形式都做疯狂的事情:

  • **%foo似乎与不能区分%foo

  • +%foo**@foo除了使用标识符%foo代替之外,似乎与没什么区别@foo绑定到的对象%fooArray

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章