我已阅读规范,但我仍然感到困惑my class
与[our] class
的区别。什么是差异以及何时使用哪个?
答案 0 :(得分:14)
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
由于变量的可见性与其在代码中的位置直接相关,词法作用域对于程序推理非常有帮助。这适用于:
在将成为 Raku 的语言设计过程的早期,子程序并没有默认具有词法作用域(并且像在 Perl 中那样具有 our
作用域),但是人们意识到词法作用域是更好的默认值.进行子程序调用总是尝试解析具有词法作用域的符号,这意味着可以在编译时报告未声明的子程序。此外,词法作用域中的符号集在编译时是固定的,并且在像子例程这样的声明性构造的情况下,例程以只读方式绑定到该符号。这也允许诸如多分派的编译时解析、编译时参数检查等。 Raku 语言的未来版本很可能会在词法范围内的程序元素上指定越来越多的编译时检查。
既然词法作用域这么好,为什么 our
(也称为包)作用域存在?简而言之,因为:
is export
共享的内容,但是..包允许符号的命名空间。例如,如果我想在同一代码中同时为 HTTP 和 WebSockets 使用 Cro 客户端,我可以愉快地同时使用它们,并将它们分别称为 Cro::HTTP::Client
和 Cro::WebSocket::Client
。
包由包声明符引入,例如 class
、module
、grammar
和(带有警告)role
。 our
声明将在封闭的包结构中进行安装。
这些包最终存在于名为 GLOBAL
的顶级包中 - 这是合适的,因为它们实际上是全局可见的。如果我们声明一个 our
范围的变量,那么它就是一个全局变量(尽管希望是一个命名空间变量),关于这个已经写得足够多了,我们知道我们应该停下来思考一下,想知道全局变量是否是最好的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...
}
词法包也可以嵌套并包含 our
范围的变量,但最终不要全局可见(除非我们以某种方式选择将它们泄漏出去)。
不同的 Raku 程序元素已被指定为默认范围:
my
) 范围has
范围(仅通过方法分派可见)our
) 范围our
) 范围实际上,最常共享的内容默认为包作用域,其余的则不然。 (变量确实迫使我们明确选择一个范围,但最常见的选择也是最短的一个。)
就我个人而言,我不愿意让某事物比语言默认值更明显,但是我经常会让它们不那么明显(例如,{{1 }} 用于内部使用的常量,以及我用来构建实现细节的类)。当我可以通过在全局可见的包中公开 my
范围的变量来做某事时,我仍然通常更愿意将其设为 our
范围并提供 my
(导出)或sub
(由于位于包范围的 method
上而可见)来控制对它的访问,以便在未来为自己争取一些灵活性。我认为如果我给自己空间让自己在未来做出正确的选择而不会给任何人带来不便,那么现在做出错误的选择是可以的。 :-)
总结:
class
范围my
范围用于您计划 my
的事物,但请记住,导出会将符号放入使用者的单一词法范围中并存在名称冲突的风险,因此在导出特别是通用名称时要深思熟虑< /li>
export
用于要共享的内容,以及何时需要使用命名空间以避免冲突our
范围,因此明确编写 our
应该暂停思考答案 1 :(得分:6)
my
与 our
的区别主要与生成符号表有关。例如:
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
在实践中,这意味着 our
范围内的任何内容都可以通过为包标识符添加前缀($Foo::c
或 Foo::<$c>
是同义词)轻松共享给外部世界,并且任何 my
{1}} 范围不是现成的——尽管您当然可以通过例如 getter subs 来提供对它的访问。
大多数时候您会想要使用 my
。大多数变量只属于它们当前的范围,没有任何业务达到峰值。但 our
在某些情况下可能很有用:
constant
暗示 our
范围)。因此,您可以通过使用 package Colors { constant red = 1; constant blue = 2; }
然后将它们引用为 Colors::red
CoolModule::set-preferences( ... )
。 (虽然这里也可以使用动态变量来达到很好的效果)。我相信其他人会在其他时候评论 our
范围是有用的,但这些是我自己的经验。
答案 2 :(得分:4)
与变量一样,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!
对模块内部的类使用my
。您当然可以通过标记它们is export
来使这些本地符号可用于导入代码。