變量名以一個(gè)叫做魔符 sigil 的特殊字符開頭, 后面跟著一個(gè)可選的第二個(gè)叫做 twigil
的特殊字符, 然后是一個(gè)標(biāo)識(shí)符.
Sigils
符號(hào) | 類型約束 | 默認(rèn)類型 | Flattens | Assignment |
---|---|---|---|---|
$ | Mu (no type constraint) | Any | No | item |
& | Callable | Callable | No | item |
@ | Positional | Array | Yes | list |
% | Associative | Hash | Yes | list |
例子:
my $square = 9 ** 2;
my @array = 1, 2, 3; # Array variable with three elements
my %hash = London => 'UK', Berlin => 'Germany';
默認(rèn)類型可以使用 is
關(guān)鍵字設(shè)置锨络。
class FailHash is Hash {
has Bool $!final = False;
multi method AT-KEY ( ::?CLASS:D: Str:D \key ){
fail X::OutOfRange.new(:what("Hash key"), :got(key), :range(self.keys)) if $!final && !self.EXISTS-KEY(key);
callsame
}
method finalize() {
$!final = True
}
}
my %h is FailHash = oranges => "round", bananas => "bendy";
say %h<oranges>;
# OUTPUT ?round
?
%h.finalize;
say %h<cherry>;
CATCH { default { put .^name, ': ', .Str } }
# OUTPUT ?X::OutOfRange: Hash key out of range. Is: cherry, should be in (oranges bananas)?
不帶符號(hào)的變量也是可行的, 查看 無符號(hào)變量.
項(xiàng)和列表賦值
有兩種類型的賦值, item 賦值和 list 賦值. 兩者都使用 = 號(hào)操作符. 根據(jù) = 號(hào)左邊的語(yǔ)法來區(qū)別 = 是 item 賦值還是 list 賦值.
Item 賦值把等號(hào)右側(cè)的值放到左側(cè)的變量(容器)中.
例如, 數(shù)組變量(@符號(hào))在列表賦值時(shí)清空數(shù)組自身, 然后把等號(hào)右側(cè)的值都放進(jìn)數(shù)組自身中. 跟 Item 賦值相比, 這意味著等號(hào)左側(cè)的變量類型始終是 Array, 不管右側(cè)是什么類型.
賦值類型(item 或 list)取決于當(dāng)前表達(dá)式或聲明符看到的第一個(gè)上下文:
my $foo = 5; # item assignment
say $foo.perl; # 5
my @bar = 7, 9; # list assignment
say @bar.WHAT; # Array
say @bar.perl; # [7, 9]
(my $baz) = 11, 13; # list assignment
say $baz.WHAT; # Parcel
say $baz.perl; # (11, 13)
因此, 包含在列表賦值中的賦值行為依賴于表達(dá)式或包含表達(dá)式的聲明符。
例如, 如果內(nèi)部賦值是一個(gè)聲明符(例如 my), 就使用 item 賦值, 它比逗號(hào)和列表賦值的優(yōu)先級(jí)更高:
my @array;
@array = my $num = 42, "str"; # item assignment: uses declarator
say @array.perl; # [42, "str"] (an Array)
say $num.perl; # 42 (a Num)
類似地, 如果內(nèi)部賦值是一個(gè)用于聲明符初始化的表達(dá)式, 則內(nèi)部表達(dá)式的上下文決定賦值的類型:
my $num;
my @array = $num = 42, "str"; # item assignment: uses expression
say @array.perl; # [42, "str"] (an Array)
say $num.perl; # 42 (a Num)
my ( @foo, $bar );
@foo = ($bar) = 42, "str"; # list assignment: uses parens
say @foo.perl; # [42, "str"] (an Array)
say $bar.perl; # $(42, "str") (a Parcel)
然而, 如果內(nèi)部賦值既不是聲明符又不是表達(dá)式, 而是更大的表達(dá)式的一部分, 更大的表達(dá)式的上下文決定賦值的類型:
my ( @array, $num );
@array = $num = 42, "str"; # list assignment
say @array.perl; # [42, "str"] (an Array)
say $num.perl; # [42, "str"] (an Array)
這是因?yàn)檎麄€(gè)表達(dá)式是 @array = $num = 42, "str"
, 而 $num = 42
不是單獨(dú)的表達(dá)式.
查看操作符獲取關(guān)于優(yōu)先級(jí)的更多詳情京髓。
無符號(hào)變量
在 Perl 6 中創(chuàng)建不帶符號(hào)的變量也是可能的:
my \degrees = pi / 180;
my \θ = 15 * degrees;
然而, 這些無符號(hào)變量并不創(chuàng)建容器. 那意味著上面的 degrees
和 θ
實(shí)際上直接代表 Nums
. 為了說明, 我們定義一個(gè)無符號(hào)變量后再賦值:
θ = 3; # Dies with the error "Cannot modify an immutable Num"
無符號(hào)變量不強(qiáng)制上下文, 所以它們可被用于原樣地傳遞某些東西:
sub logged(&f, |args) {
say('Calling ' ~ &f.name ~ ' with arguments ' ~ args.perl);
my \result = f(|args);
# ^^^^^^^ not enforcing any context here
say(&f.name ~ ' returned ' ~ result.perl);
return |result;
}
Twigils
Twigils
影響變量的作用域
僻澎。請(qǐng)記住 twigils 對(duì)基本的魔符插值沒有影響声诸,那就是民镜,如果 $a
內(nèi)插, $^a
, $*a
, $=a
, $?a
, $.a
, 等等也會(huì)內(nèi)插. 它僅僅取決于 $
.
Twigil | Scope |
---|---|
* | 動(dòng)態(tài)的 |
! | 屬性(類成員) |
? | 編譯時(shí)變量 |
. | 方法(并非真正的變量) |
< | 匹配對(duì)象索引(并非真正的變量) |
^ | 自我聲明的形式位置參數(shù) |
: | 自我聲明的形式命名參數(shù) |
= | Pod 變量 |
~ | 子語(yǔ)言 |
* Twigil
動(dòng)態(tài)變量通過 caller 查找, 不是通過外部作用域公罕。例如:
my $lexical = 1;
my $*dynamic1 = 10;
my $*dynamic2 = 100;
sub say-all() {
say "$lexical, $*dynamic1, $*dynamic2";
}
# prints 1, 10, 100
say-all();
{
my $lexical = 2;
my $*dynamic1 = 11;
$*dynamic2 = 101; # 注意,這兒沒有使用 my 來聲明
# prints 1, 11, 101
say-all();
}
# prints 1, 10, 101
say-all();
第一次調(diào)用 &say-all
時(shí), 就像你期望的一樣, 它打印 "1, 10, 100"∪荼矗可是第二次它打印 "1, 11, 101"自脯。 這是因?yàn)?$lexical
不是在調(diào)用者的作用域內(nèi)被查找, 而是在 &say-all
被定義的作用域里被查找的。這兩個(gè)動(dòng)態(tài)作用域變量在調(diào)用者的作用域內(nèi)被查找, 所以值為 11
和 101
斤富。第三次調(diào)用 &say-all
后, $*dynamic1
不再是 11 了. 但是 $*dynamic2
仍然是 101膏潮。這源于我們?cè)趬K中聲明了一個(gè)新的動(dòng)態(tài)變量 $*dynamic1
的事實(shí)并且沒有像我們對(duì)待 $*dynamic2
那樣把值賦值給舊的變量。
動(dòng)態(tài)變量與其他變量類型在引用一個(gè)未聲明的動(dòng)態(tài)變量上不同的是前者不是一個(gè)編譯時(shí)錯(cuò)誤满力,而是運(yùn)行時(shí) failure焕参,這樣一個(gè)動(dòng)態(tài)變量可以在未定義時(shí)使用只要在把它用作任何其它東西的時(shí)候檢查它是否定義過:
sub foo() {
$*FOO // 'foo';
}
say foo; # -> 'foo'
my $*FOO = 'bar';
say foo; # -> 'bar'
! Twigil
屬性是變量, 存在于每個(gè)類的實(shí)例中. 通過 !
符號(hào)它們可以從類的里面直接被訪問到:
class Point {
has $.x;
has $.y;
method Str() {
"($!x, $!y)"
}
}
注意屬性是怎樣被聲明為 $.x
和 $.y
的, 但是仍然能夠通過 $!x
和 $!y
訪問到屬性. 這是因?yàn)?在 Perl 6 中, 所有的屬性都是私有的
, 并且在類中能使用 $!attribute-name
直接訪問這些屬性. Perl 6 能自動(dòng)為你生成訪問方法. 關(guān)于對(duì)象、類和它們的屬性和方法的詳情, 請(qǐng)查看面向?qū)ο?/a>.
? Twigil
編譯時(shí)"常量", 可通過 ?
twigil 訪問. 編譯器對(duì)它們很熟悉, 并且編譯后不能被修改. 常用的一個(gè)例子如下:
say "$?FILE: $?LINE"; # prints "hello.pl: 23" if this is the 23 line of a
# file named "hello.pl".
關(guān)于這些特殊變量的列表請(qǐng)查看編譯時(shí)變量油额。
盡管不能在運(yùn)行時(shí)改變它們, 用戶可以(重新)定義這種常量.
constant $?TABSTOP = 4; # this causes leading tabs in a heredoc or in a POD
# block's virtual margin to be counted as 4 spaces.
. Twigil
.
twigil 真的不是用于變量的. 實(shí)際上, 看下面的代碼:
class Point {
has $.x;
has $.y;
method Str() {
"($.x, $.y)" # 注意我們這次使用 . 而不是 !
}
}
對(duì) self
(自身)調(diào)用了方法 x
和方法 y
, 這是自動(dòng)為你生成的, 因?yàn)樵谀懵暶髂愕膶傩缘臅r(shí)候, 你使用的是 .
twigil 叠纷。 注意, 子類可能會(huì)覆蓋那些方法. 如果你不想這個(gè)發(fā)生, 請(qǐng)使用 $!x
和 $!y
代替。
.
twigil 只是調(diào)用了一個(gè)方法也表明下面是可能的
class SaySomething {
method a() { say "a"; }
method b() { $.a; }
}
SaySomething.b; # prints "a"
關(guān)于對(duì)象悔耘、類和它們的屬性和方法的詳情, 請(qǐng)查看面向?qū)ο?/a>.
< Twigil
<
twigil 是 $/<...>
的別名, 其中, $/
是匹配變量. 關(guān)于匹配變量的更多詳情請(qǐng)查看 $/變量和類型匹配
^ Twigil
^
twigil 為 block 塊 或 子例程 聲明了一個(gè)形式位置參數(shù). 形如 $^variable
的變量是一種占位變量. 它們可用在裸代碼塊中來聲明代碼塊的形式參數(shù). 看下面代碼中的塊:
for ^4 {
say "$^seconds follows $^first";
}
它打印出:
1 follows 0
3 follows 2
有兩個(gè)形式參數(shù)讲岁,就是 $first
和 $second
. 注意, 盡管 $^second
在代碼中出現(xiàn)的比 $^first
早, $^first
依然是代碼塊中的第一個(gè)形式參數(shù). 這是因?yàn)檎嘉环兞渴且?Unicode 順序排序的.
子例程也能使用占位符變量, 但是只有在子例程沒有顯式的參數(shù)列表時(shí)才行. 這對(duì)普通的塊也適用
sub say-it { say $^a; } # valid
sub say-it() { say $^a; } # invalid
{ say $^a; } # valid
-> $x, $y, $x { say $^a; } # 非法, 已經(jīng)有參數(shù)列表 $x,$y,$x 了
占位符變量語(yǔ)法上不能有類型限制. 也注意, 也不能使用單個(gè)大寫字母的占位符變量, 如 $^A
: Twigil
:
twigil 為塊或子例程聲明了一個(gè)形式命名參數(shù)我擂。使用這種形式聲明的變量也是占位符變量的一種類型衬以。因此適用于使用 ^
twigil 聲明的變量的東西在這兒也適用(除了它們不是位置的以外, 因此沒有使用 Unicode 順序排序)。所以這個(gè):
say { $:add ?? $^a + $^b !! $^a - $^b }( 4, 5 ) :!add
# OUTPUT:
# -1
查看 ^獲取關(guān)于占位符變量的更多細(xì)節(jié)校摩。
= Twigil
=
twigil 用于訪問 Pod 變量看峻。當(dāng)前文件中的每個(gè) Pod 塊都能通過一個(gè) Pod 對(duì)象訪問到, 例如 $=data
, $=SYNOPSIS
或 =UserBlock
, 即:一個(gè)和想要的塊同名的變量加上一個(gè) =
twigil。
=begin Foo
...
=end Foo
#after that, $=Foo gives you all Foo-Pod-blocks
您可以通過 $=pod
訪問 Pod 樹衙吩,它包含所有作為分級(jí)數(shù)據(jù)結(jié)構(gòu)的Pod結(jié)構(gòu)互妓。
請(qǐng)注意,所有這些 $=someBlockName
都支持位置和關(guān)聯(lián)角色坤塞。
~ Twigil
注意: Slangs(俚語(yǔ))在 Rakudo 中還沒有被實(shí)現(xiàn)冯勉。 NYI = Not Yet Implemented.
~
twigil 是指子語(yǔ)言(稱為俚語(yǔ))。下面是有用的:
變量名 | 說 明 |
---|---|
$~MAIN | the current main language (e.g. Perl statements) |
$~Quote | the current root of quoting language |
$~Quasi | the current root of quasiquoting language |
$~Regex | the current root of regex language |
$~Trans | the current root of transliteration language |
$~P5Regex | the current root of the Perl 5 regex language |
你在你當(dāng)前的詞法作用域中擴(kuò)充這些語(yǔ)言摹芙。
use MONKEY-TYPING;
augment slang Regex { # derive from $~Regex and then modify $~Regex
token backslash:std<\Y> { YY };
}
變量聲明符和作用域
通常, 使用 my
關(guān)鍵字創(chuàng)建一個(gè)新的變量就足夠了:
my $amazing-variable = "World";
say "Hello $amazing-variable!"; # Hello World!
然而, 有很多聲明符能在 Twigils 的能力之外改變作用域的細(xì)節(jié)灼狰。
聲明符 | 作用 |
---|---|
my | 作為詞法作用域名字的開頭 |
our | 作為包作用域名字的開頭 |
has | 作為屬性名的開頭 |
anon | 作為私有名字的開頭 |
state | 作為詞法作用域但是持久名字的開頭 |
augment | 給已存在的名字添加定義 |
supersede | 替換已存在名字的定義 |
還有兩個(gè)類似于聲明符的前綴, 但是作用于預(yù)定義變量:
前綴 | 作用 |
---|---|
temp | 在作用域的最后恢復(fù)變量的值 |
let | 如果 block 成功退出就恢復(fù)變量的值 |
my 聲明符
使用 my
聲明一個(gè)變量給變量一個(gè)詞法作用域. 這意味著變量只在當(dāng)前塊中存在.例如:
{
my $foo = "bar";
say $foo; # -> "bar"
}
say $foo; # !!! "Variable '$foo' is not declared"
它拋出異常,因?yàn)橹灰覀冊(cè)谕粋€(gè)作用域內(nèi) $foo
才被定義. 此外, 詞法作用域意味著變量能在新的作用域內(nèi)被臨時(shí)地重新定義:
my $location = "outside";
sub outer-location {
# Not redefined:
say $location;
}
outer-location; # -> "outside"
sub in-building {
my $location = "inside";
say $location;
}
in-building; # -> "inside"
outer-location; # -> "outside"
如果變量被重新定義了, 任何引用外部變量的代碼會(huì)繼續(xù)引用外部變量.
所以, 在這兒, &outer-location
仍然打印外部的 $location
:
sub new-location {
my $location = "nowhere"
outer-location;
}
new-location; # -> "outside"
為了讓 new-location()
能打印 nowwhere
, 需要使用 *
twigil 讓 $location
變?yōu)閯?dòng)態(tài)變量.
對(duì)于子例程來說, my
是默認(rèn)作用域, 所以 my sub x( ) { }
和 sub x( ) { }
是一樣的.
our 聲明符
our 跟 my
的作用類似, 除了把別名引入到符號(hào)表之外:
module M {
our $Var;
# $Var available here
}
# Available as $M::Var here.
聲明一組變量
聲明符 my
和 our
接收一組擴(kuò)在圓括號(hào)中的變量作為參數(shù)來一次性聲明多個(gè)變量。
my (@a, $s, %h);
這可以和解構(gòu)賦值結(jié)合使用浮禾。任何對(duì)這樣一個(gè)列表的賦值會(huì)取得左側(cè)列表中提供的元素?cái)?shù)量并且從右側(cè)列表中把對(duì)應(yīng)的值賦值給它們交胚。沒有得到賦值的元素會(huì)根據(jù)變量的類型得到一個(gè)未定義值。
my (Str $a, Str $b, Int $c) = <a b>;
say [$a, $b, $c].perl;
# OUTPUT?["a", "b", Int]
?
要把列表解構(gòu)到一個(gè)單個(gè)的值中, 通過使用 ($var,)
創(chuàng)建一個(gè)帶有一個(gè)值的列表字面值盈电。當(dāng)使用了一個(gè)變量聲明符時(shí)只在單個(gè)變量周圍提供一個(gè)圓括號(hào)就足夠了蝴簇。
sub f { 1,2,3 };
my ($a) = f;
say $a.perl;
# OUTPUT?1
?
要跳過列表中的元素, 使用匿名狀態(tài)變量 $
。
my ($,$a,$,%h) = ('a', 'b', [1,2,3], {:1th});
say [$a, %h].perl;
# OUTPUT?["b", {:th(1)}]
?
has 聲明符
has
作用在類的實(shí)例或 role 的屬性上, 還有類或 roles 的方法上. has 隱式作用于方法上, 所以 has method x() {}
和 method x() {}
做得是相同的事情匆帚。
has method x( ) { }
等價(jià)于:
method x( ) { }
anon 聲明符
anon
聲明符阻止符號(hào)本安裝在詞法作用域內(nèi), 還有方法表中, 和其它任何地方.
例如, 你可以使用 anon
聲明一個(gè)知道自己名字的子例程, 但是仍然不會(huì)被安裝到作用域內(nèi):
my %operations =
half => anon sub half($x) { $x / 2 },
square => anon sub square($x) { $x * $x },
;
say %operations<square>.name; # square
say %operations<square>(8); # 64
state 聲明符
state
聲明詞法作用域變量, 就像 my 那樣。然而, 初始化只發(fā)生一次, 就在正常執(zhí)行流中第一次遇見初始化的時(shí)候。因此, state 變量會(huì)在閉合塊或 程序的多次執(zhí)行之間保留它們的值互拾。
因此, 下面這個(gè)子例程:
sub a {
state @x;
state $l = 'A';
@x.push($l++);
};
say a for 1..6;
會(huì)持續(xù)增加 $l
并在每次被調(diào)用時(shí)把它追加到 @x 中, 所以它會(huì)打印出:
[A]
[A B]
[A B C]
[A B C D]
[A B C D E]
[A B C D E F]
This works per "clone" of the containing code object, as in this example:
({ state $i = 1; $i++.say; } xx 3).map: {$_(), $_()}; # says 1 then 2 thrice
注意均践,這不是一個(gè)線程安全的解構(gòu), 當(dāng)同一個(gè) block 的同一個(gè)克隆運(yùn)行在多個(gè)線程中時(shí)。要知道方法只有每個(gè)類一個(gè)克隆摩幔,而不是每個(gè)對(duì)象彤委。
至于 my
,聲明多個(gè)狀態(tài)變量必須放置在圓括號(hào)中, 而聲明一個(gè)單一變量或衡,圓括號(hào)可以省略焦影。
請(qǐng)注意,許多操作符都伴隨著隱式綁定封断,什么會(huì)導(dǎo)致超距作用斯辰。使用 .clone
或強(qiáng)迫創(chuàng)建一個(gè)可以綁定的新容器。
my @a;
sub f() {
state $i;
$i++;
@a.push: "k$i" => $i # <-- .clone goes here
};
f for 1..3;
dd @a; # ?Array $var = $[:k1(3), :k2(3), :k3(3)]?
所有的狀態(tài)變量都是線程間共享的坡疼。這個(gè)結(jié)果可能是你不希望得到的或危險(xiǎn)的彬呻。
sub code(){ state $i = 0; say ++$i; $i };
await
start { loop { last if code() >= 5 } },
start { loop { last if code() >= 5 } };
# OUTPUT?1
2
3
4
4
3
5
?
# OUTPUT?2
1
3
4
5
?
# many other more or less odd variations can be produced
$ 變量
和顯式地聲明命名狀態(tài)變量一樣, $
能夠用作不帶顯式狀態(tài)聲明的匿名狀態(tài)變量。
say "1-a 2-b 3-c".subst(:g, /\d/, {<one two three>[$++]});
# OUTPUT?one-a two-b three-c
?
更進(jìn)一步, 狀態(tài)變量不需要存在于子例程中柄瑰。你可以, 舉個(gè)例子, 在單行程序中使用 $
在文件中編號(hào)行號(hào)闸氮。
perl6 -ne 'say ++$ ~ " $_"' example.txt
實(shí)際上詞法范圍內(nèi)每個(gè)對(duì) $
的引用都是是一個(gè)單獨(dú)的變量。
perl6 -e '{ say ++$; say $++ } for ^5'
# OUTPUT?1
0
2
1
3
2
4
3
5
4
?
如果在作用域內(nèi)你需要多次引用 $
的值, 那么它應(yīng)該被拷貝到一個(gè)新的變量中教沾。
sub foo() {
given ++$ {
when 1 {
say "one";
}
when 2 {
say "two";
}
when 3 {
say "three";
}
default {
say "many";
}
}
}
foo() for ^3;
# OUTPUT?one
two
three
?
@ 變量
和 $
變量類似, 也有一個(gè)位置匿名狀態(tài)變量 @
蒲跨。
sub foo($x) {
say (@).push($x);
}
foo($_) for ^3;
# OUTPUT:
# [0]
# [0 1]
# [0 1 2]
這里的 @
是用圓括號(hào)括起來了以和名為 @.push
的類成員變量消除歧義。索引訪問并不需要這種歧義授翻,但你需要拷貝這個(gè)值或悲,以便用它做任何有用的事情。
sub foo($x) {
my $v = @;
$v[$x] = $x;
say $v;
}
foo($_) for ^3;
# OUTPUT:
# [0]
# [0 1]
# [0 1 2]
就和 $
一樣, 作用域中的每次提及 @
就引入了一個(gè)新的匿名數(shù)組堪唐。
% 變量
最后, 還有一個(gè)關(guān)聯(lián)匿名狀態(tài)變量 %
巡语。
sub foo($x) {
say (%).push($x => $x);
}
foo($_) for ^3;
# OUTPUT:
# 0 => 0
# 0 => 0, 1 => 1
# 0 => 0, 1 => 1, 2 => 2
關(guān)于歧義的同樣警告適用。正如你可能期望淮菠,索引訪問也有可能(使用復(fù)制以使之有用)男公。
sub foo($x) {
my $v = %;
$v{$x} = $x;
say $v;
}
foo($_) for ^3;
# OUTPUT:
# 0 => 0
# 0 => 0, 1 => 1
# 0 => 0, 1 => 1, 2 => 2
就像其它的匿名狀態(tài)變量一樣, 在給定作用域中每次提及 %
最終都會(huì)引入一個(gè)單獨(dú)的變量。
augment 聲明符
使用 augment
, 你可以給已經(jīng)存在的類或 grammars 增加屬性和方法.
因?yàn)轭愅ǔJ褂?our 作用域, 因此是全局的, 這意味著修改全局狀態(tài), 這是強(qiáng)烈不鼓勵(lì)的, 對(duì)于大部分情況, 有更好的方法.
# don't do this
use MONKEY-TYPING;
augment class Int {
method is-answer { self == 42 }
}
say 42.is-answer; # True
temp 前綴
像 my 一樣, temp 在作用域的末尾恢復(fù)舊的變量值. 然而, temp 不創(chuàng)建新的變量.
my $in = 0; # temp will "entangle" the global variable with the call stack
# that keeps the calls at the bottom in order.
sub f(*@c) {
(temp $in)++;
"<f>\n"
~ @c>>.indent($in).join("\n")
~ (+@c ?? "\n" !! "")
~ '</f>'
};
sub g(*@c) {
(temp $in)++;
"<g>\n"
~ @c>>.indent($in).join("\n")
~ (+@c ?? "\n" !! "")
~ "</g>"
};
print g(g(f(g()), g(), f()));
# OUTPUT:
# <g>
# <g>
# <f>
# <g>
# </g>
# </f>
# <g>
# </g>
# <f>
# </f>
# </g>
# </g>
let 前綴
跟 temp 類似, 如果 block 沒有成功退出則恢復(fù)之前的值兜材。成功的退出意味著該 block 返回了一個(gè)定義過的值或一個(gè)列表理澎。
my $answer = 42;
{
let $answer = 84;
die if not Bool.pick;
CATCH {
default { say "it's been reset :(" }
}
say "we made it 84 sticks!";
}
say $answer;
在上面的例子中, 如果 Bool.pick
返回 true, 那么答案會(huì)保持為 84, 因?yàn)槟莻€(gè) block 返回了一個(gè)定義了的值(say 返回 true)。
否則那個(gè) die
語(yǔ)句會(huì)讓那個(gè) block 不成功地退出, 把答案重新設(shè)置為 42曙寡。
類型約束和初始化
變量可以有類型約束, 約束在聲明符和變量名之間:
my Int $x = 42;
$x = 'a string'; # throws an X::TypeCheck::Assignment error
CATCH { default { put .^name, ': ', .Str } }
# OUTPUT: X::TypeCheck::Assignment: Type check failed in assignment to $x; expected Int but got Str ("a string")
如果一個(gè)標(biāo)量有類型約束但是沒有初始值, 它會(huì)使用類型約束的類型對(duì)象來初始化.
my Int $x;
say $x.^name; # Int
say $x.defined; # False
沒有顯式類型約束的標(biāo)量的類型為 Mu, 但是默認(rèn)會(huì)是 Any 類型的對(duì)象.
帶有 @ 符號(hào)的變量會(huì)被初始化為空的數(shù)組; 帶有 % 符號(hào)的變量會(huì)被初始化為空的散列.
變量的默認(rèn)值可以使用 is default
特性設(shè)置, 通過把 Nil 賦值給變量來重新應(yīng)用默認(rèn)值:
my Real $product is default(1);
say $product; # 1
$produce *= 5;
say $product; # 5
$product = Nil;
say $product; # 1
默認(rèn)的有定義的變量指令
為了強(qiáng)制所有的變量擁有一個(gè)有定義的約束, 使用 use variables :D
指令糠爬。這個(gè)指令是詞法作用域的并且可以使用 use variables :_
指令進(jìn)行切換。
use variables :D;
my Int $i;
# OUTPUT?===SORRY!=== Error while compiling <tmp>
Variable definition of type Int:D (implicit :D by pragma) requires an initializer ...
my Int $i = 1; # that works
{ use variables :_; my Int $i; } # 在這個(gè) block 中關(guān)掉它
請(qǐng)注意, 賦值 Nil 會(huì)把這個(gè)變量恢復(fù)為它的默認(rèn)值举庶。一個(gè)有定義的約束類型的默認(rèn)值是類型名加上 :D
(例如 Int:D
)执隧。That means a definedness contraint is no guarantee of definedness. 這只適用于變量初始化, 不適用于簽名。
特殊變量
Pre-defined lexical variables
每個(gè)代碼塊中都有3個(gè)特別的變量:
變量 | 意義 |
---|---|
$_ | 特殊變量 |
$/ | 正則匹配 |
$! | 異常 |
$_
$_
是特殊變量,在沒有顯式標(biāo)識(shí)的代碼塊中镀琉,它是默認(rèn)參數(shù)峦嗤。所以諸如 for @array { ... }
和 given $var { ... }
之類的結(jié)構(gòu)會(huì)將變量綁定給 $_
.
for <a b c> { say $_ } # sets $_ to 'a', 'b' and 'c' in turn
say $_ for <a b c>; # same, even though it's not a block
given 'a' { say $_ } # sets $_ to 'a'
say $_ given 'a'; # same, 盡管這不是一個(gè)塊
CATCH 塊將 $_
設(shè)置為捕獲到的異常。 ~~
智能匹配操作符屋摔。
對(duì) $_
調(diào)用一個(gè)方法可以省略特殊變量 $_
的名字烁设,從而寫的更短:
.say; # 與 $_.say 相同
m/regex/
和 /regex/
正則匹配 和 s/regex/subst/
替換是作用于 $_
上的.
say "Looking for strings with non-alphabetic characters...";
for <ab:c d$e fgh ij*> {
.say if m/<!alpha>/;
}
輸出:
Looking for strings with non-alphabetic characters...
ab:c
d$e
ij*
$/
$/
是匹配變量。它存儲(chǔ)著最近一次正則匹配的結(jié)果钓试,通常包含 Match 類型的對(duì)象装黑。
'abc 12' ~~ /\w+/; # 設(shè)置 $/ 為一個(gè)Match 對(duì)象
say $/.Str; # abc
Grammar.parse
方法會(huì)把調(diào)用者的 $/
設(shè)置為 Match object
的結(jié)果」看下面的代碼:
use XML::Grammar; # panda install XML
XML.Grammar.parse("<p>some text</p>");
say $/;
# OUTPUT:
# ?<p>some text</p>?
# root => ?<p>some text</p>?
# name => ?p?
# child => ?some text?
# text => ?some text?
# textnode => ?some text?
# element => ?<p>some text</p>?
# name => ?p?
# child => ?some text?
# text => ?some text?
# textnode => ?some text?
其他匹配變量是 $/
元素的別名:
$0 # same as $/[0]
$1 # same as $/[1]
$<named> # same as $/<named>
位置屬性
如果正則中有捕獲分組, $/
中會(huì)有位置屬性. 它們由圓括號(hào)組成.
'abbbbbcdddddeffg' ~~ / a (b+) c (d+ef+) g /;
say $/[0]; # ?bbbbb?
say $/[1]; # ?dddddeff?
這些捕獲分組也能使用 $0
,$1
,$2
等便捷形式取得:
say $0; # ?bbbbb?
say $1; # ?dddddeff?
要獲取所有的位置屬性, 使用 $/.list
, @$/
,@( )
中的任意一個(gè)都可以:
say @().join; # bbbbbdddddeff
命名屬性
如果正則中有命名捕獲分組, $/
可以有命名屬性, 或者正則調(diào)用了另一個(gè)正則:
'I.... see?' ~~ / \w+ $<punctuation>=[ <-[\w\s]>+ ] \s* $<final-word> = [ \w+ . ] /;
say $/<punctuation>; # ?....?
say $/<final-word>; # ?see??
這些命名捕獲分組也能使用便捷形式的 $<named>
獲取:
say $<punctuation>; # ?....?
say $<final-word>; # ?see??
要獲取所有的命名屬性, 使用 $/.hash
, %$/
, %()
中的任何一個(gè):
say %().join; # "punctuation ....final-word see?"
$! 變量
$!
是錯(cuò)誤變量. 如果 try
block 或語(yǔ)句前綴捕獲到異常, 那個(gè)異常就會(huì)被存儲(chǔ)在 $!
中恋谭。如果沒有捕獲到異常, 那么 $!
會(huì)被設(shè)置為 Any 類型對(duì)象。
注意, CATCH
塊不設(shè)置 $!
挽鞠。CATCH 在 block 中把 $_
設(shè)置為捕獲到的異常疚颊。
編譯時(shí)變量
Compile-time Variables | 說明 |
---|---|
$?FILE | 所在文件 |
$?LINE | 所在行 |
::?CLASS | 所在類 |
&?ROUTINE | 所在子例程 |
&?BLOCK | 所在塊 |
%?LANG | What is the current set of interwoven languages? |
%?RESOURCES | The files associated with the "Distribution" of the current compilation unit. |
for '.' {
.Str.say when !.IO.d;
.IO.dir()>>.&?BLOCK when .IO.d # lets recurse a little!
}
其它編譯時(shí)變量:
Compile-time Variables | 說明 |
---|---|
$?PACKAGE | 所在包 |
$?MODULE | 所在模塊 |
$?CLASS | 所在類(as variable) |
$?ROLE | 所在角色(as variable) |
$?GRAMMAR | 所在 grammar |
$?TABSTOP | 在 heredoc 或 虛擬邊距中 tab 有多少空格 |
$?USAGE | 從 MAIN 程序的簽名中生成的使用信息 |
$?ENC | Str.encode/Buf.decode/various IO 方法的默認(rèn)編碼. |
動(dòng)態(tài)變量
Dynamic Variable | 說明 |
---|---|
$*ARGFILES | 神奇的命令行輸入句柄 |
@*ARGS | 來自命令行的參數(shù) |
$*IN | 標(biāo)準(zhǔn)輸入文件句柄, AKA stdin |
$*OUT | 標(biāo)準(zhǔn)輸出文件句柄, AKA stdout |
$*ERR | 標(biāo)準(zhǔn)錯(cuò)誤文件句柄, AKA stderr |
%*ENV | 環(huán)境變量 |
$*REPO | 存儲(chǔ)安裝過的/加載了的模塊信息的變量 |
$*TZ | 系統(tǒng)的本地時(shí)區(qū). |
$*CWD | 當(dāng)前工作目錄. |
$*KERNEL | 在哪個(gè)內(nèi)核下運(yùn)行 |
$*DISTRO | 在哪個(gè)操作系統(tǒng)分發(fā)下運(yùn)行 |
$*VM | 在哪個(gè)虛擬機(jī)下運(yùn)行 |
$*PERL | 在哪個(gè) Perl 下運(yùn)行 |
$*PID | 當(dāng)前進(jìn)程的進(jìn)程 ID |
$*PROGRAM-NAME | 當(dāng)前可執(zhí)行程序的路徑就像它通過命令行鍵入一樣, 或 -e 如果 perl 引用了 -e 標(biāo)記 |
$*PROGRAM | 正被執(zhí)行的 Perl 程序的位置( 以 IO::Path 對(duì)象的形式) |
$*EXECUTABLE | 當(dāng)前運(yùn)行的可執(zhí)行 perl 的絕對(duì)路徑 |
$*EXECUTABLE-NAME | 當(dāng)前運(yùn)行的可執(zhí)行 perl 程序的名字。(e.g. perl6-p, perl6-m, Niecza.exe) |
$*USER | 正在運(yùn)行該程序的用戶. 它是一個(gè)被求值為 "username (uid)" 的對(duì)象. 它只有在被當(dāng)作字符串時(shí)才被求值為用戶名, 如果被當(dāng)作數(shù)字則被求值為數(shù)值化的用戶 id信认。 |
$*GROUP | 運(yùn)行程序的用戶的主要組. 它是被計(jì)算為 "groupname (gid)" 的對(duì)象.它只有在被當(dāng)作字符串時(shí)才被求值為組名, 如果被當(dāng)作數(shù)字則被求值為數(shù)值化的組 id材义。 |
$*HOME | 代表當(dāng)前運(yùn)行程序的用戶家目錄的 IO::Path 對(duì)象。如果家目錄不確定則為 Nil狮杨。 |
$*SPEC | 程序運(yùn)行的平臺(tái)的合適的 IO::Spec 子類, 對(duì)于特定操作系統(tǒng)代碼,使用智能匹配: say "We are on Windows!" if $*SPEC ~~ IO::Spec::Win32 |
$*TMPDIR | 代表著 "系統(tǒng)臨時(shí)目錄" 的 IO::Path 對(duì)象 |
$*TOLERANCE | 由 <=~=> 操作符使用并且任何依賴它的操作, 來決定兩個(gè)值是否近似地相等, 默認(rèn)為 1e-15母截。 |
$*THREAD | 代表當(dāng)前執(zhí)行線程的 Thread 對(duì)象。 |
$*SCHEDULER | 代表當(dāng)前默認(rèn)調(diào)度程序的 ThreadPoolScheduler 對(duì)象橄教。 |
注意 $*SCHEDULER
的用法:
對(duì)于當(dāng)前的 Rakudo, 這個(gè)默認(rèn)在方法 .hyper
和 .race
上采用最大 16 個(gè)線程。要更改線程的最大數(shù)量, 要么在運(yùn)行 perl 之前設(shè)置環(huán)境變量 RAKUDO_MAX_THREADS 的值, 要么在使用 .hyper 或 .race 之前創(chuàng)建一個(gè)默認(rèn)改變了的作用域的拷貝:
my $*SCHEDULER = ThreadPoolScheduler.new( max_threads => 64 );
這種行為在 spec 測(cè)試中沒有被測(cè)試并且還會(huì)變化喘漏。