Perl 6 中的變量

變量名以一個(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)被查找, 所以值為 11101斤富。第三次調(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.

聲明一組變量

聲明符 myour 接收一組擴(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() {} 做得是相同的事情匆帚。

查看面向?qū)ο?/a>獲取更多文檔和例子熬词。

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ì)變化喘漏。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末护蝶,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子翩迈,更是在濱河造成了極大的恐慌持灰,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,843評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件负饲,死亡現(xiàn)場(chǎng)離奇詭異堤魁,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)返十,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門妥泉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人洞坑,你說我怎么就攤上這事盲链。” “怎么了?”我有些...
    開封第一講書人閱讀 163,187評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵刽沾,是天一觀的道長(zhǎng)本慕。 經(jīng)常有香客問我,道長(zhǎng)侧漓,這世上最難降的妖魔是什么锅尘? 我笑而不...
    開封第一講書人閱讀 58,264評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮布蔗,結(jié)果婚禮上鉴象,老公的妹妹穿的比我還像新娘。我一直安慰自己何鸡,他們只是感情好纺弊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,289評(píng)論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著骡男,像睡著了一般淆游。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上隔盛,一...
    開封第一講書人閱讀 51,231評(píng)論 1 299
  • 那天犹菱,我揣著相機(jī)與錄音,去河邊找鬼吮炕。 笑死腊脱,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的龙亲。 我是一名探鬼主播陕凹,決...
    沈念sama閱讀 40,116評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼泻蚊,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼浅妆!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起规求,我...
    開封第一講書人閱讀 38,945評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤拂盯,失蹤者是張志新(化名)和其女友劉穎佑女,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谈竿,經(jīng)...
    沈念sama閱讀 45,367評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡团驱,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,581評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了空凸。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嚎花。...
    茶點(diǎn)故事閱讀 39,754評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖劫恒,靈堂內(nèi)的尸體忽然破棺而出贩幻,到底是詐尸還是另有隱情轿腺,我是刑警寧澤,帶...
    沈念sama閱讀 35,458評(píng)論 5 344
  • 正文 年R本政府宣布丛楚,位于F島的核電站族壳,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏趣些。R本人自食惡果不足惜仿荆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,068評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望坏平。 院中可真熱鬧拢操,春花似錦、人聲如沸舶替。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,692評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)顾瞪。三九已至舔庶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間陈醒,已是汗流浹背惕橙。 一陣腳步聲響...
    開封第一講書人閱讀 32,842評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留钉跷,地道東北人弥鹦。 一個(gè)月前我還...
    沈念sama閱讀 47,797評(píng)論 2 369
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像爷辙,于是被迫代替她去往敵國(guó)和親彬坏。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,654評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容