Raku 中 (Any) 的含义是什么 - 特别是 ()?

Ros*_*ill 14 raku

这是 Raku 的一个实验:

> my $x
(Any)
> my $y=1
1
> my @a=[1, 2]
[1 2]
> my %h=a=>'b'
{a => b}
> say "nil" unless $x
nil
Run Code Online (Sandbox Code Playgroud)

我可以看到它[]表示一个数组文字,{}一个哈希文字。

我还可以看到它的(Any)行为类似于 nil - 在上面显示的布尔上下文中返回 false。

我觉得(Any)有趣。文档告诉我这Any只是 Raku 中的神类之一。但是()周围的括号Any告诉我什么?

Eli*_*sen 11

当您使用 REPL 时,表达式的结果使用say. 该say函数调用.gist表达式上的函数。

Any是一个类型对象。类型对象有一个.gist方法可以将括号放在它们周围。

put功能几乎是一样的say功能,但它调用.Str的表达功能。这会产生警告,因为您无法真正对类型对象进行字符串化。观察差异:

$ raku -e 'say Any'
(Any)

# raku -e 'put Any'
Use of uninitialized value of type Any in string context.
Methods .^name, .raku, .gist, or .say can be used to stringify it to something meaningful.
  in block <unit> at -e line 1
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅类和对象类型系统类型对象

  • 但确实,对于新手来说,它可能看起来像一个单元素列表。也许我们将来可以改变一些事情? (2认同)
  • 但这是 Raku 中的一个普遍“问题”:`(foo)` 并不是**一个元素列表,它只是一些东西的分组。`(foo,)`(注意逗号)*是*一个单元素列表。 (2认同)
  • jjmerelo:如果进行了任何更改,我会推荐“(Type:U)”或“Type:U”,尽管最终“(Type)”只是一个需要学习的习惯用法。遗憾的是,您无法覆盖/包装 Mu 的要点并让它自动适用于其他所有内容 - 让一个模块将对象键入为“Type”但以绿色/灰色/黄色等形式键入对象可能会很酷。 (2认同)
  • 我已经为此启动了问题解决票:https://github.com/Raku/problem-solving/issues/194 (2认同)

use*_*601 5

除了 lizmat 的出色回答之外,解释这里发生的事情可能也很重要。

当您说 时my $foo,您实际上是在说my Any $foo1 而当您说 时my @foo,您隐含地说了一些更接近于my Any @foowhich 相同的内容my Array[Any] $foo(但在位置容器中)。这使您可以将任何内容放入数组中,因为它的类型是Any.

当您访问一个未定义的对象时,它会返回一个未定义的值——但该值仍然是类型化的。碰巧的是,默认情况下,类型是Any. 然而,我们可以改变一些事情,它可能会变得更加清晰:

my Str $foo;
say $foo;    # a Str that's undefined, so '(Str)';
my $bar;     # implicitly typed Any
say $bar;    # an Any that's undefined, so '(Any)';

my Int @foo = 0, 1, 2;
say @foo[0];   # an Int defined as 0, so '0'
say @foo[1];   # an Int defined as 1, so '1'
say @foo[3];   # an Int that's undefined, so '(Int)'
Run Code Online (Sandbox Code Playgroud)

正如 lizmat 在她的回答中指出的那样,(Type)是方法的默认表示,.gist.say用于未定义的值。2

它们不返回的原因Nil是因为根据定义,每个调用它的方法都会Nil返回Nil(除了一些例外,比如Bool它返回的地方False)——它有点像 Objective-C 的nil. 但是一个未定义的类型对象仍然有用途:例如,你仍然可以调用它的方法,只要它们不访问属性。有时这可能是一个非常有用的属性,它实际上使您能够执行以下操作:

  my Foo $foo .= new;
Run Code Online (Sandbox Code Playgroud)

哪个是语法糖

  my Foo $foo;
  $foo = $foo.new;
Run Code Online (Sandbox Code Playgroud)

$foo是一个未定义的类型对象,所以我们实际上仍然调用Foo.new.


  1. 作为raiph正确地在评论中指出,我应该指出,这不是正是发生了什么事情,但是从最终用户的角度来看,是足够接近和更复杂。
  2. 人们总是可以覆盖这一点,我已经为我的一些类做了这个,这些类的名称与添加明确前缀的内置函数可疑地接近或相同,因此我不会混淆它们。

  • .oO(“当你说‘我的$foo’时,你就隐含地在说‘我的任何$foo’。”我对此说,“当意识的钟声敲响它甜美的音调时,[教学便利](https: //www.youtube.com/watch?v=ORjyXcLDd9M&amp;t=1m31s)在他们的区域内有重量,所以在威特的最后,真相响起;首先响起的是苏格拉底的怀疑。”或者,更平淡地说,当一个人写‘ my $foo`,你隐式地写了“my Mu $foo is default(Any)”。这是相当合理的脚注。反过来,这表明它属于梯子的第一级。其中,转身,表明这是一个谎言。“等等。什么?”) (3认同)
  • 罗斯·阿特里尔:我可以理解。这只是 Raku 开发的习俗之一。一旦您理解 (Type) 意味着“Type 类型的未定义值”)您就会习惯它。也许可以将 `:U` 添加为 `(Any:U)`,它明确是一个未定义的值/类型对象。我尝试看看是否可以在模块中实现这一点,但由于某种原因包装现有方法不起作用=\ (2认同)

Bra*_*ert 5

有一个非常简单的答案。

Any是一个类。具体来说,它是每个其他类的默认基类。

在 Raku 中,您可以像传递实例一样传递类。

my $a = 1;
my $b = $a.WHAT;

say $b;
# (Int)
Run Code Online (Sandbox Code Playgroud)

问题是,如果您尝试将类用作实例,则会发生不好的事情。

say $b + 4;
# ERROR: … must be an object instance of type 'Int', not a type object of type 'Int'.
Run Code Online (Sandbox Code Playgroud)

当您使用 REPL 时,它会自动调用.gist并打印结果。

.gist 是为了让人类能够理解价值是什么。

那么为什么要在类名周围添加括号呢?

对我来说,这样做是为了告诉你它不是一个Str或其他一些实例。

say 'Str'; # say calls .gist
# Str

say 'abc'.WHAT;
# (Str)

say 'abc'.WHAT.^name;
# Str

say 'abc'.^name;
# Str
Run Code Online (Sandbox Code Playgroud)

除了其中之一之外,所有的都是Str类的实例。
(猜猜是哪一个。)


基本上,括号告诉您尝试将其用作实例是错误的。

  • 谢谢布拉德。这个答案很有帮助,因为它揭示了对象实例和类型对象之间的区别。总结句也很有用。 (3认同)