包是命名程序元素的嵌套命名空间。 模块、类、语法等都是包的类型。就像目录中的文件一样,如果命名元素是本地的,你通常可以使用它们的短名称来引用它们,或者如果它们的范围允许,可以使用包含命名空间的较长名称来消除歧义。
名称§
包名称是任何可以作为变量名称一部分的合法内容(不包括 sigil)。这包括
my ; # simple identifierssay Foo::Bar.baz; # calling a method; OUTPUT: «Þor is mighty»say Foo::Bar::zape; # compound identifiers separated by ::; OUTPUT: «zipi»my = 'Bar';say ::()::quux; # compound identifiers with interpolations; OUTPUT: «42»$42; # numeric names$!; # certain punctuation variables
包本身并没有真正的标识;它们可以仅仅是模块或类名的一部分,例如。它们更类似于命名空间而不是模块。如果存在同名模块,它将捕获包的标识。
:ver<0> ;:ver<1> ;say Foo.^ver; # OUTPUT: «1»
语法允许声明的包使用版本以及授权 auth
,但实际上,它被忽略了;只有模块、类和其他更高阶类型对象具有可能包含 auth
和 ver
的标识。
:ver<0>:auth<bar> ;say Foo.^auth;# OUTPUT: «(exit code 1) No such method 'auth' for invocant of type# 'Perl6::Metamodel::PackageHOW' ...
包限定名§
普通的包限定名看起来像这样:$Foo::Bar::quux
,它将是包 Foo::Bar
中的 $quux
变量;Foo::Bar::zape
将表示同一包中的 &zape
变量。
有时将 sigil 与变量名放在一起更清晰,因此另一种写法是
Foo::Bar::<$quux>
这对于 Foo«&zape»
变量不起作用,因为 sub
默认情况下具有词法作用域。名称在编译时解析,因为变量名是常量。我们可以访问 Bar
中的其余变量(如上面的示例所示),因为类默认情况下具有包作用域。
如果 ::
之前的名称部分为空,则表示包未指定,必须搜索。通常这意味着在主 sigil 之后紧跟的初始 ::
对编译时已知的名称是无操作的,尽管 ::()
也可用于引入插值。此外,在没有其他 sigil 的情况下,::
可以用作它自己的 sigil,表示有意使用尚未声明的包名。
伪包§
MY | 当前词法作用域中的符号(又名 $?SCOPE) |
OUR | 当前包中的符号(又名 $?PACKAGE) |
CORE | 最外层词法作用域,标准 Raku 的定义 |
GLOBAL | 解释器范围的包符号,实际上是 UNIT::GLOBAL |
PROCESS | 与进程相关的全局变量(超级全局变量)。动态变量查找将查找的最后一个位置。 |
COMPILING | 正在编译的作用域中的词法符号 |
CALLER | 直接调用者的词法作用域中的动态符号 |
CALLERS | 任何调用者的词法作用域中的动态符号 |
DYNAMIC | 我或任何调用者的词法作用域中的动态符号 |
OUTER | 下一个外层词法作用域中的符号 |
OUTERS | 任何外层词法作用域中的符号 |
LEXICAL | 我或任何外层词法作用域中的动态符号 |
UNIT | 编译单元的最外层词法作用域中的符号 |
SETTING | 单元的 DSL 中的词法符号(通常是 CORE) |
PARENT | 此包的父包(或词法作用域)中的符号 |
CLIENT | 来自不同包的最近 CALLER |
文件的范围称为 UNIT
,但其外部存在一个或多个词法作用域,对应于语言设置(在其他文化中通常称为序言)。因此,SETTING
作用域等效于 UNIT::OUTERS
。对于标准的 Raku 程序,SETTING
与 CORE
相同,但各种启动选项(如 -n
或 -p
)可以将您置于特定领域语言中,在这种情况下,CORE
仍然是标准语言的作用域,而 SETTING
代表定义 DSL 的作用域,该 DSL 充当当前文件的设置。当用作名称中间的搜索词时,SETTING
包括其所有外层作用域,直到 CORE
。要仅获取设置的最外层作用域,请使用 UNIT::OUTER
代替。
查找名称§
插值到名称§
你可以使用 字符串插值 将一个字符串插值到包名或变量名中,使用 ::($expr)
,在通常放置包名或变量名的地方。该字符串允许包含额外的 ::
实例,这些实例将被解释为包嵌套。你只能插值整个名称,因为该结构以 ::
开头,并且要么立即结束,要么以括号外的另一个 ::
继续。大多数符号引用都是使用这种表示法完成的
my = "Foo";my = "Bar";my = "Foo::Bar";$::() # lexically-scoped $Bar$::("MY::$bar") # lexically-scoped $Bar$::("OUR::$bar") # package-scoped $Bar$::("GLOBAL::$bar") # global $Bar$::("PROCESS::$bar") # process $Bar$::("PARENT::$bar") # current package's parent's $Bar$::() # $Foo::Bar@::()::baz # @Foo::Bar::baz@::()::Bar::baz # @Foo::Bar::baz@::()baz # ILLEGAL at compile time (no operator baz)@::()::()::baz # @Foo::Bar::baz
初始的 ::
并不意味着全局;这里作为插值语法的一部分,它甚至不意味着包。在插值 ::()
组件之后,间接名称的查找方式与在原始源代码中存在时完全相同,优先级首先给领先的伪包名,然后给词法范围内的名称(向外搜索范围,以 CORE
结束)。当前包最后被搜索。
使用 MY
伪包将查找限制在当前词法范围,使用 OUR
将范围限制在当前包范围。
同样,类名和方法名也可以插值
does with-methoddoes with-method ;my = 'a-class';say ::().a-method; # OUTPUT: «in-a-method of a-class»= 'b-class';say ::().a-method; # OUTPUT: «in-a-method of b-class»my = 'a-method';say a-class."$what-method"(); # OUTPUT: «in-a-method of a-class»= 'another-method';say a-class."$what-method"(); # OUTPUT: «in-another-method»
直接查找§
要在不扫描的情况下直接在包的符号表中查找,将包名视为哈希
Foo::Bar:: # same as &Foo::Bar::bazPROCESS::<$IN> # same as $*INFoo::<::Bar><::Baz> # same as Foo::Bar::Baz
与 ::()
符号引用不同,这不会解析 ::
的参数,也不会从该初始点开始启动命名空间扫描。此外,对于常量下标,它保证在编译时解析符号。
你不能在正则表达式中使用这种直接查找,除非你发出 MONKEY-SEE-NO-EVAL
编译指示。此措施的主要目的是避免用户输入在外部执行。
空伪包与普通名称搜索的搜索列表相同。也就是说,以下所有含义都相同
::::<$foo>
它们都向外扫描词法范围,然后是当前包范围(尽管当“严格”生效时,包范围随后被禁止)。
包查找§
将包对象本身作为哈希对象进行下标,其键是变量名,包括任何符号。包对象可以通过使用 ::
后缀从类型名派生
MyType::<$foo>
类成员查找§
方法(包括自动生成的方法,例如公共属性的访问器)存储在类元对象中,可以通过 lookup 方法查找。
Str.^lookup('chars')
全局变量§
解释器全局变量驻留在 GLOBAL
包中。用户的程序从 GLOBAL
包开始,因此主线代码中的“our”声明默认情况下进入该包。进程范围变量驻留在 PROCESS
包中。大多数预定义的全局变量,如 $*UID
和 $*PID
,实际上是进程全局变量。
模块的编程使用§
有时能够以编程方式定义和使用模块非常有用。这是一个实际的例子。
假设我们有一系列模块,其模块文件位于这样的目录树中
lib/ TomtomMaps/ Example/ # a directory of example file modules programmatically # created from the Tomtom Maps SDK A01.rakumod #... C09.rakumod #...
模块 TomtomMaps::Example::C09
看起来像这样
unit ;# ensure you use the 'our' declaratorour sub print-example(, # filehandle open for writing:)
我们可以像这样访问和使用子例程
use lib 'lib';my = 'TomtomMaps::Example';my = 'C09';my = "::";# you must use the runtime 'require', not the compile-time 'use'require ::();my = open "./example-.html", :w;my = 'ghghfxnnhrgfsWE.mmn';# execute the subroutine&::()::print-example(, :); # the map's html file is written.close;