明确命名的返回值?

时间:2016-01-26 14:33:47

标签: return-value perl6

在Go(and G++?)中,以下是一个常见的习语:

func sqr(x int) (n int, err error) {
    n = x * x
    err = nil
    return
}

(n int, err error)显式枚举返回值的名称和类型。在我看来,这有很多优点,我喜欢它。

在Perl 6中,我们可以:

my sub sqr (Int:D $x) returns Int:D {
    $x ** 2;
}

返回是隐式的,这让我有些不舒服(我们可以使用return明确表示),但您可能会注意到指定了返回类型(事实上它是<子> D efined )。

不出所料,没有明显的方法可以通过名称显式返回值,但我很好奇,因为Perl(尤其是6)在各方面都可以进行广泛修改,如果有办法实现这一点。 1

1 然而,它可能是hacky,但太过于hacky而且我会避免将它用于“真实”的东西。

2 个答案:

答案 0 :(得分:7)

如果所有其他方法都失败了,你总是可以写自己的俚语。

但是,我提出了两种不太复杂的方法,第一种使用固定名称的动态变量,第二种使用用户定义名称的rw参数:

multi sub trait_mod:<is>(Routine:D \r, :$dynrv!) {
    r.wrap(-> | { my $*rv; callsame; $*rv })
}

multi sub trait_mod:<is>(Routine:D \r, :$pararv!) {
    r.wrap(-> |c { my $rv; callwith(|c, $rv); $rv })
}

sub double($x) is dynrv {
    $*rv = $x * 2;
    return 666; # discarded
}

sub triple($x, $y is rw) is pararv {
    $y = $x * 3;
    return 666; # discarded
}

say double 42;
say triple 42;

请注意,这仅支持单个返回值,但我有一些想法可以使多个可以工作...

编辑:例如这样:

multi sub trait_mod:<is>(Routine:D \r, :@dynrv!) {
    r.wrap(-> | {
        my @rv = Nil xx @dynrv;
        my $*rv = Map.new(@dynrv Z=> @rv);
        callsame;
        @dynrv > 1 ?? @rv !! @rv[0];
    })
}

multi sub trait_mod:<is>(Routine:D \r, Int :$pararv!) {
    r.wrap(-> |c {
        my @rv = Nil xx $pararv;
        callwith(|c, |@rv);
        $pararv > 1 ?? @rv !! @rv[0];
    })
}

sub divmod($a, $b) is dynrv<d m> {
    $*rv<d> = $a div $b;
    $*rv<m> = $a mod $b;
}

sub plusmin($a, $b, $p is rw, $m is rw) is pararv(2) {
    $p = $a + $b;
    $m = $a - $b;
}

say divmod 14, 3;
say plusmin 14, 3;

答案 1 :(得分:4)

虽然可以使用俚语来获得您想要的内容,但我相信它们是解决此问题的错误尺寸解决方案。首先,cat的 Go 示例返回错误信息以及(Int)。我建议Perl 6的方法是简单地使用&fail返回 Fail 对象,调用者可以使用.defined//运算符进行测试;

if $something_wrong {
  return fail "Dang!  Even the squaring function isn't working today."
}
else {
  return $x ** 2
}

我知道这并没有按要求记录双返回值,但是您是否希望使用显式变量来获得特殊的带外数据?如果不是错误数据而是其他信息怎么办? 假设我们想要返回带有复活节彩蛋消息的(Int)。在这种情况下,由于额外数据是不同的类型(Str),我们可以使用.Str方法在角色中运行时混合,如果在字符串上下文中使用返回值,则返回消息。

return $x * $x but "Suprise!  Bet you weren't expecting that!"

或者,如果额外数据属于同一类型,我们可以明确地混合匿名角色。假设我们想要返回一个带有.size属性的(Int);

return $x but role { has $.size = calculate_size() }

最后,您可以通过声明角色然后使用子集来定义您自己的(Int)类型来明确记录您的返回类型;

role Size { has UInt:D $.size = 0 }
subset MyInt of Int where Size;

sub sqr(Int:D $x, UInt:D :$size = 12) returns MyInt:D {
  return $x * $x but Size($size)
}

my $square5 = sqr(5);
say "5 squared is $square5 with size $square5.size()."
# prints: 5 squared is 25 with size 12.

详情位于S14S12 - Anonymous mixin roles