仅当 Str 表示整数时,如何将其转换为 Int ?

How can I convert a Str to an Int only when it represents an integer?

在 Perl 6 中,您可以指定可以强制转换为的类型。例如,您需要一个 Int,但得到可以转换为 Int 的其他东西。当您不想 IntStr 的单独候选者时,这很方便,其中字符串表示整数值。

但是,转换似乎有点激进,因为转换不仅改变类型而且愿意改变数据。这在一定程度上是合并更改类型和将数字截断为整数的预期操作的问题。从概念上讲,这些是不同的想法,但它们在 Str.Int 中交织在一起(实际上夹在 Numeric 的旁路):

sub foo ( Int:D() $n ) { put "Got <$n> of type {$n.^name}" }
foo( 80 );     # Got <80> of type Int
foo( '99' );   # Got <99> of type Int
foo( 1.5 );    # Got <1> of type Int
foo( '1.5' );  # Got <1> of type Int

尝试将其限制为 Str 也好不到哪儿去:

sub foo ( Int:D(Str:D) $n ) { put "Got <$n> of type {$n.^name}" }
foo( '1.5' );  # Got <1> of type Int

我可以制作一些看起来最容易理解的适配器:

multi foo ( Int:D $n ) {
    put "Got <$n> of type {$n.^name}"
    }
multi foo ( Str:D $n where { $^n.Int == $^n.Numeric } ) {
    foo( $n.Int );
    }

foo( '1.5' );  # Cannot resolve ...

我或许可以想出一些子集,但这并不令人满意。所以诀窍是,我可以在不更改值的情况下这样强制执行吗(即使它更改了表示形式)?


事实证明此功能已损坏且没有修复时间表:RT 132980。基本上,不强制执行目标类型。文档已更新。我的建议是完全不要使用它。

一个可能的签名是

Numeric() $ where Int

或者,限制为字符串,

Numeric(Str:D) $ where Int

Int:D(Any) 在 Rakudo 中的工作方式是创建一个接受 Any 的多候选,将其转换为 Int,并使用结果调用您的原始子程序。

如果您自己做,您可以更好地控制它的工作方式。

proto sub foo ( Int:D() $n ) {*}

multi sub foo ( Any:D $n ) {
  my $i = try $n.Numeric.narrow;

  if $i ~~ Int:D {

    samewith $i

  } else {

    X::TypeCheck::Binding::Parameter.new(

      # there are more arguments that should be added here
      got => $n,
      expected => Int:D(),

    ).throw

  }
}

multi sub foo ( Int:D $n ) { put "Got <$n> of type {$n.^name}" }