当前位置: 首页 > 知识库问答 >
问题:

像Int(酷)这样的胁迫有什么意义?

林祯
2023-03-14

关于函数的Perl6网站说

强制类型可以帮助您在例程中拥有特定类型,但可以接受更广泛的输入。调用例程时,参数将自动转换为较窄的类型。

sub double(Int(Cool) $x) {
    2 * $x
}

say double '21';    # 42
say double Any;     # Type check failed in binding $x; expected 'Cool' but got 'Any'

这里Int是参数将被强制的目标类型,Cool是例程接受作为输入的类型。

但潜艇的意义何在?$x不就是一个Int?为什么要限制调用者为参数实现Cool

这个例子让我倍感困惑,因为Int已经很酷了。所以我做了一个示例,其中类型不共享层次结构:

class Foo { method foomethod { say 'foomethod' } }
class Bar {}

class Quux is Foo {
# class Quux { # compile error
  method Bar { Bar.new }
}

sub foo(Bar(Foo) $c) {
  say $c.WHAT;    # (Bar)
  # $c.foomethod  # fails if uncommented: Method 'foomethod' not found for invocant of class 'Bar'
}

foo(Quux.new)

在这里,foo的调用者被限制提供一个可以转换为BarFoo,但是foo甚至不能在$c上调用Foo的方法因为它的类型是Bar。那么,为什么foo首先会关心待强制类型是Foo呢?

有人能解释一下吗?链接到适当的留档和规范的一部分也是值得赞赏的。我在那里找不到任何有用的东西。


共有3个答案

张成济
2023-03-14

我是不是漏了什么?我不是Perl 6的专家,但它的语法似乎允许一个人独立地指定什么输入类型是允许的,以及输入将如何呈现给函数。

限制允许的输入是有用的,因为这意味着当使用无意义的参数调用函数时,代码将导致错误,而不是静默(无用)类型转换。

我认为这两种类型不处于等级关系的例子没有意义。

湛鸿雪
2023-03-14

它所做的是接受一个Cool的子类型的值,并尝试将其转换为Int。在这一点上,它是一个Int,无论它以前是什么。

所以呢

sub double ( Int(Cool) $n ) { $n * 2 }

实际上可以被认为是(我认为这就是它在Rakudo实际实现的方式)

# Int is a subtype of Cool otherwise it would be Any or Mu
proto sub double ( Cool $n ) {*}

# this has the interior parts that you write
multi sub double (  Int $n ) { $n * 2 }

# this is what the compiler writes for you
multi sub double ( Cool $n ) {
    # calls the other multi since it is now an Int
    samewith Int($n);
}

因此,它接受Int、Str、Rat、FatRat、Num、Array、Hash等中的任意一个,并在调用

say double '  5  '; # 25
say double 2.5;     # 4
say double [0,0,0]; # 6
say double { a => 0, b => 0 }; # 4

您可以将其限制为Cool而不是Any,因为所有Cool值本质上都需要提供对Int的强制。

:(Int(任何) $ )可以缩短为仅仅:(Int() $ )

您可能这样做的原因是您需要它在sub中是一个Int,因为您正在调用其他代码,这些代码使用不同的类型执行不同的操作。

sub example ( Int(Cool) $n ) returns Int {
    other-multi( $n ) * $n;
}

multi sub other-multi ( Int $ ) { 10 }
multi sub other-multi ( Any $ ) {  1 }

say example 5;   # 50
say example 4.5; # 40

在这种特殊情况下,您可以将其作为其中一个来编写

sub example ( Cool $n ) returns Int {
    other-multi( Int($n) ) * Int($n);
}

sub example ( Cool $n ) returns Int {
    my $temp = Int($n);
    other-multi( $temp ) * $temp;
}

sub example ( Cool $n is copy ) returns Int {
    $n = Int($n);
    other-multi( $n ) * $n;
}

没有一个比用签名来强迫你的更清楚。

通常,对于这样一个简单的函数,您可以使用其中的一个,它可能会做您想要的事情。

my &double = * * 2; # WhateverCode
my &double = * × 2; # ditto

my &double = { $_ * 2 };       # bare block
my &double = { $^n * 2 };      # block with positional placeholder
my &double = -> $n { $n * 2 }; # pointy block

my &double = sub ( $n ) { $n * 2 } # anon sub
my &double = anon sub double ( $n ) { $n * 2 } # anon sub with name

my &double = &infix:<*>.assuming(*,2); # curried
my &double = &infix:<*>.assuming(2);

sub double ( $n ) { $n * 2 } # same as :( Any $n )

谯和煦
2023-03-14
匿名用户

更新今天回顾了这个答案,我得出结论,我完全误解了@musiKk的意思。这在@darch的问题和@musiKk的回答中表现得最为明显:

@达奇:或者你的问题是为什么人们更喜欢Int(酷)而不是Int(任何)?如果是这样的话,那就是要问的问题。

@这正是我的问题

回顾许多其他答案,我发现没有一个像我现在认为的那样解决了这个问题。

当然,我可能错了,所以我决定保持原来的问题不变,特别是保持标题不变,保持这个答案不变,而是写一个新的答案,解决@darch的重新表述。

我们可以宣布:

sub double (Int $x) { ... } # Accept only Int. (No coercion.)

那么这就行了:

double(42);

但是不幸的是,输入42来回应这个:

double(prompt('')); # `prompt` returns the string the user types

导致double调用失败,绑定$x时类型检查失败;应为Int,但得到Str(“42”),因为42,虽然看起来像一个数字,但从技术上讲,它是一个类型为Str的字符串,我们不要求强制。

我们可以在sub的签名中引入任意值的一揽子强制:

sub double (Int(Any) $x) { ... } # Take Any value. Coerce to an Int.

或:

sub double (Int() $x)    { ... } # Same -- `Int()` coerces from Any.

现在,如果在双精度提示下键入42(提示(“”)) 123abc,强制将在运行时失败,并显示一条漂亮的错误消息:

Cannot convert string to number: trailing characters after number in '123⏏abc'

任何值的一揽子强制的一个问题是代码如下:

class City { ... } # City has no Int coercion
my City $city;
double($city);

运行时失败,消息为:“未找到类“City”发票的方法“Int”。

我们可以在无强制和任何价值的全面强制之间选择一个平衡点。

最好的强制类通常是Cool类,因为Cool值可以很好地强制其他基本类型,或者生成一个很好的错误消息:

# Accept argument of type Cool or a subclass and coerce to Int:
sub double (Int(Cool) $x) { ... }

根据这一定义,如下:

double(42);
double(prompt(''));

尽可能完美地工作,并且:

double($city);

“绑定$x时类型检查失败;预期很酷,但得到了City(City)”,对于程序员来说,这在诊断上比“类'City'的发票找不到方法'Int'要好一点。

为什么Foo会关心被胁迫的类型首先是Foo?

希望现在很明显,将强制从type限制为Foo的唯一原因是,这是一种期望成功强制为Bar值的类型(或者,可能会因为友好消息而失败)。

有人能解释一下吗?链接到适当的留档和规范的一部分也是值得赞赏的。我在那里找不到任何有用的东西。

您最初引用的文档几乎就是最终用户文档的全部内容。希望现在一切都有意义,你们都准备好了。如果没有请评论,我们将从那里开始。

 类似资料:
  • 问题内容: 当每个人都可以使用jarsigner签名时,像Java的jars一样对代码进行签名有什么意义?它如何提供安全性? 问题答案: 签名JAR文件的重点是验证它是否已被篡改。对jar文件进行签名后,您可以验证该文件未被其他人修改。这样可以确保文件源自最初签名的人。如果有人修改了文件,则签名验证过程将失败。您可以查看本文,以获取有关如何使用公钥加密执行数字签名的更多详细信息。

  • 我想知道为什么不使用这个明显简洁的表达呢?

  • 我一直在做一些欧拉项目练习,以提高我的C语言知识。 我编写了以下函数: 这将在17毫秒内计算。 但是,如果我改变路线 自 计算在2毫秒内完成。我是否遗漏了< code>pow(int,int)的一些明显的实现细节,导致第一个表达式的计算速度如此之慢?

  • ENOENT中的是什么意思? 错误不应该是: 没有这样的文件或目录 只是被命名? 有什么故事或原因吗?

  • 在中,是什么意思? 只是用命名吗? 有什么故事或原因吗?

  • 问题内容: 我是Go的新手,在浏览其他一些线程时遇到了以下代码行: 含义是什么?它是否指定将在if条件中分配某些内容(因为err似乎正在发生这种情况)?我在Wiki上找不到这种语法的示例,并且我很好奇它的用途。 问题答案: 因为返回两个值,所以如果需要它们中的任何一个,都必须在某个地方接收这些值。该是一个占位符,基本的意思是“我不关心这个特殊的返回值。” 在这里,我们只关心检查错误,而无需对实际的