我的班级和我们在 Raku(perl6) 中的班级有什么区别?

teo*_*jan 4 raku

我已经阅读了规范,但我仍然很困惑my class[our] class. 有什么区别以及何时使用哪个?

Jon*_*ton 15

my范围说明符意味着词法范围:以下其声明,符号是当前的大括号内的代码可见。因此,我们倾向于将一对花括号内的区域称为“词法范围”。例如:

sub foo($p) {
    # say $var;       # Would be a compile time error, it's not declared yet
    my $var = 1;
    if $p {
        $var += 41;   # Inner scope, $var is visible
    }
    return $var;      # Same scope that it was declared in, $var is visible
}
# say $var;           # $var is no longer available, the scope ended
Run Code Online (Sandbox Code Playgroud)

由于变量的可见性与其在代码中的位置直接相关,词法作用域对于程序推理非常有帮助。这适用于:

  • 程序员(既是因为他们自己对程序的推理,也是因为当事物具有词法作用域时可以检测和报告更多错误)
  • 编译器(词法范围允许更容易和更好的优化)
  • 诸如 IDE 之类的工具(分析和推理具有词法范围的事物要容易得多)

在将成为 Raku 的语言的设计过程的早期,子程序并没有默认具有词法作用域(并且具有our像 Perl 中的作用域),但是人们意识到词法作用域是更好的默认值。进行子程序调用总是尝试解析具有词法作用域的符号,这意味着可以在编译时报告未声明的子程序。此外,词法范围内的符号集在编译时是固定的,并且在像子例程这样的声明性构造的情况下,例程以只读方式绑定到该符号。这也允许诸如多分派的编译时解析、编译时参数检查等。Raku 语言的未来版本很可能会指定越来越多的编译时检查词法范围的程序元素。

所以如果词法范围如此好,为什么our(也称为包)范围存在?简而言之,因为:

  1. 有时我们想要比在给定的词法范围内更广泛地共享事物。我们可以声明一切词法,然后标记我们想要分享的东西is export,但是..
  2. 一旦我们到了使用许多不同库的地步,让所有东西都尝试将事物导出到消费者的单一词法范围内可能会导致很多冲突

包允许符号的命名空间。例如,如果我想在同一代码中同时为 HTTP 和 WebSockets 使用 Cro 客户端,我可以愉快地同时使用它们,并将它们分别称为Cro::HTTP::ClientCro::WebSocket::Client

包由包声明符引入,例如class, module, grammar, 和 (带有警告) role。的our声明将在封闭封装结构的安装。

这些包最终存在于名为GLOBAL-的顶级包中,这很合适,因为它们实际上是全局可见的。如果我们声明一个our-scoped 变量,那么它就是一个全局变量(尽管希望是一个命名空间变量),关于它的描述已经足够多了,我们知道我们应该停下来思考一下全局变量是否是最好的 API 决策(因为,最终,最终可见的所有内容GLOBAL都是 API 决定)。

然而,事情确实有点模糊的地方是我们可以有词法包。这些是未安装在GLOBAL. 我发现这些在进行面向对象编程时非常有用。例如,我可能有:

# This class that ends up in GLOBAL...
class Cro::HTTP::Client {
    # Lexically scoped classes, which are marked `my` and thus hidden
    # implementation details. This means I can refactor them however I
    # want, and never have to worry about downstream fallout!
    my class HTTP1Pipeline {
        # Implementation...
    }
    my class HTTP2Pipeline {
        # Implementation...
    }

    # Implementation...
}
Run Code Online (Sandbox Code Playgroud)

词法包也可以嵌套并包含our-scoped 变量,但最终不会全局可见(除非我们以某种方式选择将它们泄漏出去)。

不同的 Raku 程序元素被赋予了默认范围:

  • 子程序默认为词法 ( my) 范围
  • 方法默认为has范围(仅通过方法分派可见)
  • 类型(类、角色、语法、子集)和模块声明默认为包(our)范围
  • 常量和枚举默认为包 ( our) 范围

实际上,最常共享的内容默认为包作用域,其余的则不然。(变量确实迫使我们明确地选择一个范围,但是最常见的选择也是最短的一个类型。)

就我个人而言,我不愿意让某个东西比语言默认值更明显,但是我通常会让它们不那么明显(例如,my在供内部使用的常量上,以及在我用来构建实现细节的类上)。当我可以通过our在全局可见的包中公开-scoped 变量来做某事时,我仍然经常更喜欢将它my设为 -scoped 并提供sub(导出)或method(由于在包范围内可见class)来控制访问对它,为自己在未来购买一些灵活性。我认为如果我给自己空间让自己在未来做出正确的选择而不会给任何人带来不便,那么现在做出错误的选择是可以的。:-)

总之:

  • my范围用于所有实现细节
  • 也将my范围用于您计划做的事情export,但请记住,导出会将符号放入消费者的单一词法范围中并有名称冲突的风险,因此在导出特别是通用名称时要深思熟虑
  • 使用our的东西都是有被共享,而当它需要使用命名空间避免冲突
  • our无论如何,我们最想共享的元素默认为作用域,因此明确编写our应该暂停思考


use*_*601 6

myVSour生成符号表时区别主要是相关的。例如:

my $a;           # Create symbol <$a>  at top level
package Foo {    # Create symbol <Foo> at top level
   my  $b;       # Create symbol <$b>  in Foo scope 
   our $c;       # Create symbol <$c>  in Foo scope
}                #           and <Foo::<$c>> at top level
Run Code Online (Sandbox Code Playgroud)

在实践中,这意味着our通过在包标识符($Foo::cFoo::<$c>同义词)前加上前缀,任何有范围的东西都可以很容易地与外部世界共享,而任何有my范围的东西都不容易获得——尽管你当然可以通过例如 getter 提供对它的访问潜艇

大多数时候你会想要使用my. 大多数变量只属于它们当前的范围,没有人有任何业务高峰。但our在某些情况下可能很有用:

  • 不会毒害符号表的常量(这就是为什么,实际上, usingconstant 意味着一个our范围)。因此,您可以通过使用package Colors { constant red = 1; constant blue = 2; }然后引用它们来制作更多 C 风格的枚举/常量Colors::red
  • 应该可以访问但不需要导出的类或子类(或者不应该是因为与内置或其他模块重叠的符号)。导出符号可能很棒,但有时让包/模块命名空间提醒您使用什么东西也很好。因此,这也是在运行时通过 subs: 管理选项的好方法CoolModule::set-preferences( ... )。(虽然动态变量在这里也可以起到很好的作用)。

我相信其他人会在其他时候评论our范围是有用的,但这些是我自己的经验。


Chr*_*oph 5

与变量一样,my在词法上绑定一个名称,同时our在周围的包中另外创建一个条目。

module M {
    our class Foo {}
    class Bar {} # same as above, really
    my class Baz {}
}

say M::Foo; # ok
say M::Bar; # still ok
say M::Baz; # BOOM!
Run Code Online (Sandbox Code Playgroud)

使用my了类内部的模块。当然,您仍然可以通过标记这些本地符号来使它们可用于导入代码is export

  • @teodozjan:它不需要公开或导出,因为它是“设置”的一部分。您编写的所有代码都被包含核心内置函数的外部词法范围隐式包围,例如“Rational” (3认同)