如何指定返回的数组类型?
How to specify a returned Array type?
sub a { my @c = 1, 2, 3, 4; return @c };
sub b { my $d = [ 1, 2, 3, 4 ]; return $d };
say a().WHAT; # (Array)
say b().WHAT; # (Array)
my @e = a();
my @f = b();
say @e; # [1 2 3 4]
say @e[1]; # 2
say @f; # [[1 2 3 4]]
say @f[1]; # (Any)
# valid raku code, no errors messages
这些子例程都 return 一个数组,但 returned 数组的行为不同。在文档中明确哪种数组类型被子例程 return 编辑的正确表达式是什么?
sub b ( --> Array ) { my $d = [ 1, 2, 3, 4 ]; return $d };
say b().WHAT; # (Array)
sub b ( --> Scalar ) { my $d = [ 1, 2, 3, 4 ]; return $d };
say b().WHAT;
# Type check failed for return value; expected Scalar but got Array ([1, 2, 3, 4])
# in sub b at ...
# in block <unit> at ...
这都是关于一个尚未去容器化的 Scalar
。
您可以将 return $d
更改为 return @$d
获得相同行为的一个选择是改变 b
例程。
您已经写了“这些子例程都是 return 一个数组,但是 returned 数组的行为不同。”。但是,正如 Holli 指出的那样,b
而不是 return 绑定到 $d
的 Scalar
(后者又包含一个数组):
sub b { my $d = [ 1, 2, 3, 4 ]; return $d };
say b().VAR.WHAT; # (Scalar)
您可以通过“去容器化”$d
来更改它,例如通过添加 @
:
sub b { my $d = [ 1, 2, 3, 4 ]; return @$d };
say b().VAR.WHAT; # (Array)
my @f = b();
say @f; # [1 2 3 4]
say @f[1]; # 2
或将@f = b()
改为@f = b[]
如果您不去容器化由b
编辑的值return,那么就会出现第二个问题/机会。
不管 b
return 是什么,@f
赋值将评估分配给它的值列表。在列表上下文中,Scalar
s 保持原样(就像它们与普通 return $d
一样)。因此,如果您 而不是 将 b
更改为去容器化,那么您需要在对 @f
的赋值中这样做,如果您想要 @e
和 @f
结束相同。
这一次你不能只在前面加上 @
来这样做。因为那会拼写 @b
—— Raku 会将其解释为 @b
变量。
一种选择是写成 @f = @(b())
,但那会很丑陋/不符合习惯。另一种选择是写 @f = b[]
。这利用了 b
调用中的括号是多余的这一事实。添加 []
(一个“zen slice”)与写入 @(b)
具有相同的效果,但少了一个字符。
因此,要在列表分配中去容器化,您可以这样写:
sub b { my $d = [ 1, 2, 3, 4 ]; return $d };
say b().VAR.WHAT; # (Scalar)
my @f = b[];
say @f; # [1 2 3 4]
say @f[1]; # 2
“在文档中明确”
What would be the correct expression to make clear in the documentation which array type what is returned by the subroutine?
我不确定你问这个问题是什么意思,即使只是切换到“什么是 returned”。
我也不确定在文档中向您指出什么,即使有任何好的地方可以向您指出,相对于您的 SO 中的场景。
我确实知道,如果是我,相对于您的情况,我会发现以下文档部分 令人困惑:
Scalar containers and listy things 部分 Holli 已链接。在我看来,该部分目前是关于在 lists/arrays 中使用 Scalar
容器,这与我在上面写的 second 问题相关($d
在分配给 @f
) 的右侧列表中。但这与我写的第一个问题无关(return $d
来自 b
例程)。事情是相反的,即 Scalar
.
中有一个数组
同一页前面的 Scalar containers 部分。开场白——“尽管 Scalar
类型的对象在 Raku 中无处不在,但你很少将它们直接视为对象,因为大多数操作都会去容器化……”对我有用。但是“一个例程可以 return 一个容器,如果它被标记为 is rw
” 是更有问题的。 是真:
my $x = 23;
sub f() is rw { $x };
f() = 42;
say $x; # OUTPUT: «42»
但是没有将例程is rw
标记为return容器。可以像您一样使用 return
例程:
my $x = 23;
sub f() { return $x };
say f().VAR.WHAT; # OUTPUT: «Scalar»
原题问为什么会出现如下错误:
sub b ( --> Scalar ) { my $d = [ 1, 2, 3, 4 ]; return $d };
say b().WHAT;
# Type check failed for return value; expected Scalar but got Array ([1, 2, 3, 4])
# in sub b at ...
# in block <unit> at ...
此答案旨在详细说明 return 类型的约束,如记录 here
如果你这样做,现在你正在 returning 一个标量:
sub b( --> Scalar ) { my $x=42; my $d = $x; return $d };
say b().WHAT;
你得到一个不同的错误
Type check failed for return value; expected Scalar but got Int (42)
in sub b at scum.raku line 2
in block <unit> at scum.raku line 7
这是怎么回事?
好吧,raku 在测试类型之前会自动去容器化标量 $x - 这就是标量容器的工作方式。所以 运行 的工厂代码你应该使用具体的 return 类型约束,比如 Int、Real、Num、IntStr、Allomorph、Cool 等等。 Raku 内置类型经过精心设计,可以让编码人员精确控制此测试的级别。
但是 - 如果你想玩强力技巧,那么你可以像这样应用 --> Scalar
约束(如@raiph所述):
sub b( --> Scalar ) { my $x=42; my $d = $x.VAR; return $d };
say b().WHAT; #(Scalar)
换句话说,meta 方法 .VAR 绕过标量容器的正常透明 decont,让您测试您的 return 类型是否是顶级容器。
所以(我相信您已经从 raiph 的更好答案中了解到)请将 --> Scalar
记录为一种罕见的形式,而不是常见的 --> Array
检查。
sub a { my @c = 1, 2, 3, 4; return @c };
sub b { my $d = [ 1, 2, 3, 4 ]; return $d };
say a().WHAT; # (Array)
say b().WHAT; # (Array)
my @e = a();
my @f = b();
say @e; # [1 2 3 4]
say @e[1]; # 2
say @f; # [[1 2 3 4]]
say @f[1]; # (Any)
# valid raku code, no errors messages
这些子例程都 return 一个数组,但 returned 数组的行为不同。在文档中明确哪种数组类型被子例程 return 编辑的正确表达式是什么?
sub b ( --> Array ) { my $d = [ 1, 2, 3, 4 ]; return $d };
say b().WHAT; # (Array)
sub b ( --> Scalar ) { my $d = [ 1, 2, 3, 4 ]; return $d };
say b().WHAT;
# Type check failed for return value; expected Scalar but got Array ([1, 2, 3, 4])
# in sub b at ...
# in block <unit> at ...
这都是关于一个尚未去容器化的 Scalar
。
您可以将 return $d
更改为 return @$d
获得相同行为的一个选择是改变 b
例程。
您已经写了“这些子例程都是 return 一个数组,但是 returned 数组的行为不同。”。但是,正如 Holli 指出的那样,b
而不是 return 绑定到 $d
的 Scalar
(后者又包含一个数组):
sub b { my $d = [ 1, 2, 3, 4 ]; return $d };
say b().VAR.WHAT; # (Scalar)
您可以通过“去容器化”$d
来更改它,例如通过添加 @
:
sub b { my $d = [ 1, 2, 3, 4 ]; return @$d };
say b().VAR.WHAT; # (Array)
my @f = b();
say @f; # [1 2 3 4]
say @f[1]; # 2
或将@f = b()
改为@f = b[]
如果您不去容器化由b
编辑的值return,那么就会出现第二个问题/机会。
不管 b
return 是什么,@f
赋值将评估分配给它的值列表。在列表上下文中,Scalar
s 保持原样(就像它们与普通 return $d
一样)。因此,如果您 而不是 将 b
更改为去容器化,那么您需要在对 @f
的赋值中这样做,如果您想要 @e
和 @f
结束相同。
这一次你不能只在前面加上 @
来这样做。因为那会拼写 @b
—— Raku 会将其解释为 @b
变量。
一种选择是写成 @f = @(b())
,但那会很丑陋/不符合习惯。另一种选择是写 @f = b[]
。这利用了 b
调用中的括号是多余的这一事实。添加 []
(一个“zen slice”)与写入 @(b)
具有相同的效果,但少了一个字符。
因此,要在列表分配中去容器化,您可以这样写:
sub b { my $d = [ 1, 2, 3, 4 ]; return $d };
say b().VAR.WHAT; # (Scalar)
my @f = b[];
say @f; # [1 2 3 4]
say @f[1]; # 2
“在文档中明确”
What would be the correct expression to make clear in the documentation
which array typewhat is returned by the subroutine?
我不确定你问这个问题是什么意思,即使只是切换到“什么是 returned”。
我也不确定在文档中向您指出什么,即使有任何好的地方可以向您指出,相对于您的 SO 中的场景。
我确实知道,如果是我,相对于您的情况,我会发现以下文档部分 令人困惑:
Scalar containers and listy things 部分 Holli 已链接。在我看来,该部分目前是关于在 lists/arrays 中使用
中有一个数组Scalar
容器,这与我在上面写的 second 问题相关($d
在分配给@f
) 的右侧列表中。但这与我写的第一个问题无关(return $d
来自b
例程)。事情是相反的,即Scalar
.同一页前面的 Scalar containers 部分。开场白——“尽管
Scalar
类型的对象在 Raku 中无处不在,但你很少将它们直接视为对象,因为大多数操作都会去容器化……”对我有用。但是“一个例程可以 return 一个容器,如果它被标记为is rw
” 是更有问题的。 是真:
my $x = 23;
sub f() is rw { $x };
f() = 42;
say $x; # OUTPUT: «42»
但是没有将例程is rw
标记为return容器。可以像您一样使用 return
例程:
my $x = 23;
sub f() { return $x };
say f().VAR.WHAT; # OUTPUT: «Scalar»
原题问为什么会出现如下错误:
sub b ( --> Scalar ) { my $d = [ 1, 2, 3, 4 ]; return $d };
say b().WHAT;
# Type check failed for return value; expected Scalar but got Array ([1, 2, 3, 4])
# in sub b at ...
# in block <unit> at ...
此答案旨在详细说明 return 类型的约束,如记录 here
如果你这样做,现在你正在 returning 一个标量:
sub b( --> Scalar ) { my $x=42; my $d = $x; return $d };
say b().WHAT;
你得到一个不同的错误
Type check failed for return value; expected Scalar but got Int (42)
in sub b at scum.raku line 2
in block <unit> at scum.raku line 7
这是怎么回事?
好吧,raku 在测试类型之前会自动去容器化标量 $x - 这就是标量容器的工作方式。所以 运行 的工厂代码你应该使用具体的 return 类型约束,比如 Int、Real、Num、IntStr、Allomorph、Cool 等等。 Raku 内置类型经过精心设计,可以让编码人员精确控制此测试的级别。
但是 - 如果你想玩强力技巧,那么你可以像这样应用 --> Scalar
约束(如@raiph所述):
sub b( --> Scalar ) { my $x=42; my $d = $x.VAR; return $d };
say b().WHAT; #(Scalar)
换句话说,meta 方法 .VAR 绕过标量容器的正常透明 decont,让您测试您的 return 类型是否是顶级容器。
所以(我相信您已经从 raiph 的更好答案中了解到)请将 --> Scalar
记录为一种罕见的形式,而不是常见的 --> Array
检查。