[譯][Perl 6] 5to6-nutshell

About

  • Perl 6 documenthtml

  • 翻譯前端

  • 本翻譯意在幫助理解原文,因我的水平有限,不免會有翻譯不當,若是疑惑請在評論中指出。node

Translation

原文git

從 Perl 5到 Perl 6

簡而言之,之前作什麼如今怎麼作
吾欲以 Perl 6行 Perl 5之所爲,當何如?

這個頁面嘗試去索引從 Perl 5到 Perl 6的語法以及語義上的變化。那些在 Perl 5中正常工做的,在 Perl 6中卻要換一種寫法的語法應該被列出在這裏(而許多 Perl 6的新特性以及風格就不會)。
所以,這個頁面並非針對 Perl 6初學者的手冊或者進階文章,它是爲有着 Perl 5知識背景的 Perl 6學習者以及移植 Perl 5 代碼到 Perl 6的人員準備的技術文檔(雖然Automated Translation可能會更方便一些)。
注意當文檔中咱們說「如今」時,更多的意思是「你如今正在學習的 Perl 6」,並無暗示說 Perl 5忽然過期了,偏偏相反,大多數的咱們都深愛 Perl 5,咱們但願 Perl 5能再繼續使用好多年,事實上,咱們的重要目標之一就是讓 Perl 5和 Perl 6之間順利交互。不過,咱們也喜歡 Perl 6的設計目標,相比 Perl 5中的設計目標,更新穎,更好。因此,咱們中的大多數人都但願在下一個十年或者兩個十年,Perl 6能成爲更流行的語言,若是你想把「如今」看成將來,那也是很好的,但咱們對致使爭論的非此即彼的思想不感興趣。程序員

CPAN

參見Perl 6模塊列表
若是你使用的模塊尚未被移植到 Perl 6,並且在列表中沒有替代品,可能在 Perl 6中的使用問題尚未解決。
有不少目標是爲了在 Perl 6中usePerl 5模塊的工程:
v5模塊意在讓Rakudo自身解析 Perl 5的代碼,而後編譯成和 Perl 6一樣的字節碼。
Inline::Perl5模塊使用一個內嵌的perl解釋器運行 Perl 6腳本中調用到的Perl 5代碼。
其中,Inline::Perl5更完善,更有前途。github

語法

-> 方法調用

若是你有讀過 Perl 6的代碼,一個最明顯的地方就是方法調用語法如今使用點替代了箭頭:web

$person->name; # Perl 5
$person.name; # Perl 6

點符號即容易書寫又更加符合行業標準,不過咱們也想賦予箭頭別的使命(字符串鏈接如今使用~運算符)。
對於直到運行時期才知道名字的方法調用:正則表達式

$object->$methodname(@args); # Perl 5
$object."$methodname"(@args); # Perl 6

若是你省略了雙引號,那麼 Perl 6會認爲$methodname包含一個Method對象,而不是簡單的方法名字字符串。shell

空白

Perl 5在容許空白的使用上有着驚人的靈活性,即便是在嚴格模式(strict mode)而且打開警告(warnings)環境下:編程

# 不符合習慣,可是在 Perl 5是能夠的
say "Hello".ucfirst  ($people
    [$ i]
    ->
    name)."!"if$greeted[$i]<i;

Perl 6也支持程序員書寫自由和代碼的創造性,可是權衡語法靈活性和其一致性、肯定性、可擴展的grammar,支持一次解析以及有用的錯誤信息,集成如自定義運算符的特性,而且不會致使程序員誤用的設計目標,而且,「code golf」的作法也很重要,Perl 6的設計在概念上更簡潔而不是擊鍵上。
所以,在 Perl 5的語法的許多地方空白都是可選的,但在 Perl 6裏多是強制的或者禁止的,這些限制中的許多不太可能關係到現實生活中的 Perl 代碼(舉例來講,sigil 和變量名字之間的空格被禁止了),可是有一些可能不太幸運的和一些 Perl hacker的編程習慣風格相沖突:

  1. 參數列表的開括號以前不容許包含空白

    substr ($s, 4, 1);        # Perl 5 (這在 Perl 6 意味着傳遞了一個列表參數)
    substr($s, 4, 1);        # Perl 6
    substr $s, 4, 1;        # Perl 6 替代括號的風格
  2. 關鍵字後面要緊跟空白

    my($alpha, $beta);            # Perl 5,這在 Perl 6裏面將嘗試調用例程my()
    my ($alpha, $beta);            # Perl 6
    
    if($a < 0) { ... }            # Perl 5,在 Perl 6將會停止執行
    if ($a < 0) { ... }            # Perl 6
    if $a < 0 { ... }            # Perl 6,更符合習慣
    
    while($x-- > 5) { ... }        # Perl 5,在 Perl 6將會停止執行
    while ($x-- > 5) { ... }    # Perl 6
    while $x-- > 5 { ... }        # Perl 6,更符合習慣
  3. 前綴運算符後面或者後綴運算符、後綴環繞運算符(包含數組、哈希下標運算符)的前面不容許包含空白。

    $seen {$_} ++;        # Perl 5
    %seen{$_}++;        # Perl 6
    方法調用運算符周圍不容許出現空白:
    $customer -> name;        # Perl 5
    $customer.name;            # Perl 6
  4. 中綴運算符在可能和存在的後綴運算符或者後綴環繞運算符衝突時前面要包含空白:

    $n<1;            # Perl 5 (在 Perl 6裏面可能和後綴環繞運算符 < > 衝突)
    $n < 1;            # Perl 6

然而,你可使用unspace在 Perl 6的不容許使用空白的代碼那增長空白:

#     Perl 5
my @books = $xml->parse_file($file)            # 一些註釋
                ->findnodes("/library/book");

#  Perl 6
my @books = $xml.parse-file($file)\            # 一些註釋
                .findnodes("/library/book");

參見 Perl 6設計文檔中的S03#Minimal whitespace DWIMmeryS04#Statement parsing

Sigils

在 Perl 5中,數組和哈希使用的 sigil 取決於怎樣訪問它們,在 Perl 6裏面,不論變量怎樣被使用,sigil 是不變的 - 你能夠把他們做爲變量名字的一部分(參見 Dereferencing)。

$-標量

sigil $ 如今老是和「標量」變量一塊兒使用(好比$name),再也不用於數組索引以及哈希索引。這就是說,你仍然可使用$x[1]$x{"foo"},可是它們是做用在$x上,並不會對類似名字的@x%x有影響,它們如今能夠經過@x[1]%x{"foo"}來訪問。

@-數組

sigil @ 如今老是和「數組」變量一塊兒使用(好比@month@month[2]@month[2, 4]),再也不用於哈希值切片

%-哈希

sigil % 如今老是和「哈希」變量一塊兒使用(好比%calories%calories<apple>%calories<pear plum>),再也不用於數組鍵值切片

&-過程

sigil & 如今始終(而且再也不須要反斜槓了)引用一個命名子例程/運算符的函數對象並不會執行它們,換句話說,把函數名字看成「名詞」而不是「動詞」:

my $sub = \&foo;    # Perl 5
my $sub = &foo;        # Perl 6

callback => sub  { say @_ };    # Perl 5 - 不能直接傳遞內建過程
callback => &say;                # Perl 6 - & 給出任何過程的「名詞」形式

由於 Perl 6一旦完成編譯就不容許在做用域內添加/刪除符號,因此 Perl 6並無與 Perl 5中undef &foo;等效的語句,而且最接近 Perl 5的defined &foo;defined &::("foo")(這使用了「動態符號查找(dynamic symbol lookup)」語法)。然而,你可使用my &foo;聲明一個可修更名字的子例程,而後在運行過程當中向&foo賦值改變它。
在 Perl 5中,sigil &還能夠用來以特定的方式調用子例程,這和普通的過程調用有些許不一樣,在 Perl 6中這些特殊的格式再也不可用:

  1. &foo(...),使函數原型失效
    在 Perl 6中再也不有原型了,對你來講,這和傳遞一個代碼塊或者一個持有代碼對象的變量做爲參數沒有什麼不一樣:

    # Perl 5
    first_index {$_ > 5} @values;
    &first_index($coderef, @values);    # 禁止原型而且傳遞一個代碼塊做爲第一個參數
    
    # Perl 6
    first {$_ > 5}, @values, :k;    # :k 副詞使第一個參數返回下標
    first $coderef, @values, :k;
  2. &foo,還有 goto &foo; 用來重用調用者的參數列表或者替換調用棧的調用者

    sub foo { say "before"; &bar;     say "after" } # Perl 5
    sub foo { say "before"; bar(|@_) say "after" } # Perl 6 - 須要顯式傳遞
    
    # 建議使用Rakudo中的 .callsame
    
    sub foo { say "before"; goto &bar } # Perl 5
    
    # 建議使用Rakudo中的 .nextsame 或者 .nextwith

*-Glob

在 Perl 5中,sigil * 指向一個 GLOB 結構,繼而 Perl 可使用它存儲非詞法變量,文件句柄,過程,還有格式(?formats)(不要和 Perl 5的用來讀取目錄中的文件名的內建函數 glob()混淆了)。
你最可能在不支持詞法文件句柄,但須要傳遞文件句柄到過程時的早期 Perl 版本代碼中與 GLOB 邂逅:

# Perl 5 - 古法
sub read_2 {
    local (*H) = @_;
    return scalar(<H>), scalar(<H>);
}

open FILE, '<', $path or die;
my ($line1, $line2) = read_2(*FILE);

在翻譯到適合 Perl 6的代碼前,你可能須要重構你的 Perl 5代碼以移除對 GLOB的依賴:

# Perl 5 - 詞法文件句柄的現代用法
sub read_2 {
    my ($fh) = @_;
    return scalar(<$fh>), scalar(<$fh>);
}
open my $in_file, '<', $path or die;
my ($line1, $line2) = read_2($in_file);

而後這是可能的一個 Perl 6翻譯代碼:

# Perl 6
sub read-n($fh, $n) {
    return $fh.get xx $n;
}
my $in-file = open $path or die;
my ($line1, $line2) = read-n($in-file, 2);

[]-數組索引/切片

如今,數組的索引和切片再也不改變變量的sigil,而且在還可使用副詞控制切片的類型:

  1. 索引

    say $months[2]; # Perl 5
    say @months[2]; # Perl 6 - @ 替代 $
  2. 值切片

    say join ',', @months[6, 8..11]; # Perl 5, Perl 6
  3. 鍵值切片

    say join ',', %months[6, 8..11];    # Perl 5
    say join ',', @months[6, 8..11]:kv; # Perl 6 - @ 替代 %,而且使用 :kv 副詞

    還有注意下標括號如今並非一個特殊的語法形式,而是一個普通的後綴環繞運算符,所以檢測元素是否存在刪除元素使用副詞完成。

{}-哈希索引/切片

如今,哈希的索引和切片再也不改變變量的sigil,而且在還可使用副詞控制切片的類型。還有,花括號中的單詞下標再也不自動引用(即自動在兩邊加上雙引號),做爲替代,老是自動引用其內容的新的尖括號版本是可用的(使用和qw//引用構造相同的規則):

  1. 索引

    say $calories{"apple"}; # Perl 5
    say %calories{"apple"}; # Perl 6 - % 替代 $
    
    say $calories{apple};    # Perl 5
    say %calories<apple>;     # Perl 6 - 尖括號,% 替代 $
    say %calories«$key»;    # Perl 6 - 雙尖括號內插做爲一個 Str 列表
  2. 值切片

    say join ',', @calories{'pear', 'plum'};  # Perl 5
    say join ',', %calories{'pear', 'plum'};  # Perl 6 - % 替代 @
    say join ',', %calories<pear plum>;          # Perl 6 - (更漂亮的版本)
    my $key = 'pear plum';
    say join ',', %calories«$key»;              # Perl 6 - 在內插以後完成切分
  3. 鍵值切片

    say join ',', %calories{'pear', 'plum'};    # Perl 5
    say join ',', %calories{'pear', 'plum'}:kv; # Perl 6 - 使用 :kv 副詞
    say join ',', %calories<pear plum>:kv;        # Perl 6 - (更漂亮的版本)

    還有注意下標花括號如今再也不是一個特殊的語法形式,而是一個普通的後綴環繞運算符,所以檢測鍵是否存在鍵移除使用副詞完成。

引用的建立

在 Perl 5中,引用一個匿名數組和哈希以及過程的在它們建立的時候返回,引用一個存在的命名變量和過程使用\運算符完成。
在 Perl 6中,匿名數組和哈希以及過程依然在它們建立的時候返回,引用一個命名的過程需在它們的名字前面加一個 sigil &,引用一個存在的命名變量使用item上下文:

my $aref = [1, 2, 9];            # 同時適用於 Perl 5&6
my $href = {A => 98, Q => 99 }; # 同時適用於 Perl 5&6

my $aref =         \@aaa; # Perl 5
my $aref = item(@aaa); # Perl 6

my $href =         \%hhh; # Perl 5
my $href = item(%hhh); # Perl 6

my $sref =         \&foo; # Perl 5
my $sref =          &foo; # Perl 6

解引用

在 Perl 5中,對一整個引用解引用的語法是使用 類型-sigil 和花括號,引用放在花括號裏面,在 Perl 6中,由花括號變爲了圓括號:

# Perl 5
say         ${$scalar_ref};
say         @{$array_ref};
say keys    %{$hash_ref};
say         &{$sub_ref};

# Perl 6
say         $($scalar_ref);
say         @($array_ref);
say         %($hash_ref);
say         &($sub_ref);

注意在 Perl 5和 Perl 6中,圍繞的花括號或者括弧都常常被省略,雖然省略下降了易讀性。
在 Perl 5中,箭頭運算符->,用來單次訪問複合引用或者經過引用調用一個過程,在 Perl 6中,咱們使用點運算符.完成這一任務:

# Perl 5
say         $array_ref->[7];
say         $hash_ref->{'fire bad'};
say         $sub_ref->($foo, $bar);

# Perl 6
say         $array_ref.[7];
say         $hash_ref.{'fire bad'};
say         $sub_ref.($foo, $bar);

在最近的 Perl 5版本(5.20或者之後),一個新的特性容許使用箭頭運算符解引用,參見實驗性的後綴解引用,這個新特性和 Perl 6中的.list以及.hash方法對應:

# Perl 5.20
use experimental qw < postref >;
my @a = $array_ref->@*;
my %h = $hash_ref->%*;
my @slice = $array_ref->@[3..7];

# Perl 6
my @a = $array_ref.list;        # 或者 @($array_ref)
my %h = $hash_ref.hash;            # 或者 %($hash_ref)
my @slice = $array_ref[3..7];

「Zen」切片能夠有一樣的效果:

# Perl 6
my @a = $array_ref[];
my %h = $hash_ref{};

參見 S32/Containers

運算符

更多運算符細節請參見S03-operators
未改變的:

  • , 列表運算符

  • \+ 數值加法

  • \- 數值減法

  • * 數值乘法

  • / 數值除法

  • % 數值求餘

  • ** 數值求冪

  • ++ 數值自增

  • -- 數值自減

  • ! && || ^ 邏輯運算符,高優先級

  • not and or xor 邏輯運算符,低優先級

  • == != < > <= >= 數值比較

  • eq ne lt gt le ge 字符串比較

<=> cmp 三目運算符

在 Perl 5,這些運算符返回 -1,0 或者 1,而在 Perl 6,它們返回值對應的是 Order::LessOrder::SameOrder::More
cmp 如今叫作 leg(字符串比較),它只適用於字符串上下問比較。
<=>仍然只適用於數值上下文。
cmp在 Perl 6中同時具有<=>leg的功能,這依賴於參數的類型。

~~ 智能匹配運算符

運算符自己沒有改變,實際匹配的內容規則依賴於參數的類型,不過 Perl 6中的這些規則跟 Perl 5有很大不一樣。參見S03/Smart matching

& | ^ 字符串位運算符 數值位運算符 邏輯運算符

在 Perl 5中,$ | ^的行爲依賴於參數的內容,好比,31 | 33 的返回值和"31" | "33"是不一樣的。
在 Perl 6中,這些單字符運算符都被移除了,替代它們的是能夠強制把參數轉換到須要的內容的雙字符運算符。

# 中綴運算符 (兩個參數,左右各一個)
+&    +|    +^    按位和    按位或    按位異或    :數值
~&    ~|    ~^    按位和    按位或    按位異或    :字符串
?&    ?|    ?^    按位和    按位或    按位異或    :邏輯

# 前綴運算符 (一個參數,在運算符後)
+!    非:數值
~!    非:字符串
?!    非:邏輯 (做用和 ! 運算符同樣)

<< >> 數值左右移位運算符

+<+>取代。

say 42 << 3; # Perl 5
say 42 +< 3; # Perl 6

=> 胖逗號

在 Perl 5裏面,=>的行爲就想一個逗號,可是會自動引用(即加上雙引號)左邊的參數。
在 Perl 6裏面,=>是 Pair 運算符,這是最主要的不一樣,可是在許多狀況下行爲都和 Perl 5裏面相同。
在哈希初始化時,或者向一個指望哈希引用的方法傳遞一個參數時,=>的用法就是相同的:

# 同時適用於 Perl 5&6
my %hash = (AAA => 1, BBB => 2);
get_the_loot('diamonds', {quiet_level => 'very', quantity => 9}); # 注意花括號

在爲了避免再引用(兩邊加上雙引號)列表的一部分而使用=>做爲一種便利的方式時,或者向一個指望鍵,值,鍵,值這樣的平坦列表的方法傳遞參數時,繼續使用=>可能會破壞你的代碼,最簡單的解決方法就是將胖逗號改成普通的逗號,而後在引用左邊的參數。或者,你能夠將方法的接口改成接受一個哈希,一個比較好的解決方式就是將方法的接口改成指望 Pair,然而,這須要你當即改動全部的方法調用代碼。

# Perl 5
sub get_the_loot {
    my $loot = shift;
    my %options = @_;
    # ...
}
# 注意 這個方法調用中沒有使用花括號
get_the_loot('diamonds', quiet_level => 'very', quantity => 9);

# Perl 6,原始接口
sub get_the_loot($loot, *%options) { # * 意味着接受任何東西
    # ...
}
get_the_loot('diamonds', quiet_level => 'very', quantity => 9); # 注意 這個方法調用中沒有使用花括號

# Perl 6中,接口改成指定有效的選項
# sigil 前面的冒號表明指望一個 Pair
# 參數的鍵名字和變量相同
sub get_the_loot($loot, :$quiet_level?, :$quantity = 1) {
    # 這個版本會檢查未指望的參數
    # ...
}
get_the_loot('diamonds', quietlevel => 'very');    # 參數名字拼寫錯誤,將會拋出一個錯誤

? : 條件運算符

如今使用兩個問號替代了本來的一個問號,冒號被兩個歎號替代了。

my $result = ($score > 60)    ?    'Pass'    :    'Fail';    # Perl 5
my $result = ($score > 60)    ??    'Pass'    !!    'Fail';    # Perl 6

. 鏈接運算符

被波浪線替代。
小貼士:想象一下使用針和線「縫合」兩個字符串。

$food = 'grape'    . 'fruit';    # Perl 5
$food = 'grape'    ~ 'fruit';    # Perl 6

x 列表或者字符串重複運算符

在 Perl 5,x是重複運算符。
在標量上下文,x將會重複一個字符串,在 Perl 6裏,x會在任何上下文重複字符串。
在列表上下文,x當且僅當將列表括入圓括號中時重複當前列表,在 Perl 6,新的運算符xx將會在任何上下文重複列表。
小貼士:xx相對於x是比較長的,因此xx適用於列表。

# Perl 5
print '-' x 80;            # 打印出一行橫槓
@ones = (1) x 50;        # 一個含有80個1的列表
@ones = (5) x ones;        # 把全部元素設爲5

# Perl 6
print '-' x 80;            # 無變化
@ones = 1 xx 80;        # 再也不須要圓括號
@ones = 5 xx @ones;        # 再也不須要圓括號

.. ... 雙點、三點、範圍以及翻轉運算符

在 Perl 5,..依賴於上下文是兩個徹底不一樣的運算符。
在列表上下文,..是熟悉的範圍運算符,範圍運算在 Perl 6有許多新的改變,不過 Perl 5的範圍運算代碼不須要翻譯。
在標量上下文,.....是不爲人知的翻轉運算符,在 Perl 6中它們被fffff取代了。

字符串內插

在 Perl 5,"${foo}s"將變量名從普通的文本中分離出來,在 Perl 6中,簡單的將花括號擴展到 sigil 外便可:"{$foo}s"

複合語句

條件語句

if elsif else unless

除了條件語句兩邊的括號如今是可選的,這些關鍵字幾乎沒有變化,可是若是要使用括號,必定沒關係跟着關鍵字,不然這會被看成普通的函數調用,綁定條件表達式到一個變量也稍微有點變化:

if (my $x = dostuff()) { ... }        # Perl 5
if dostuff() -> $x { ... }            # Perl 6

在 Perl 6中你能夠繼續使用my格式,可是它的做用域再也不位於語句塊的內部,而是外部。
在 Perl 6中unless條件語句只容許單個語句塊,不容許elsif或者else子語句。

given-when

given-when結構相似於if-elsif-else語句或者 C 裏面的switch-case結構。它的普通樣式是:

given EXPR {
    when EXPR { ... }
    when EXPR { ... }
    default { ... }
}

根據這個最簡單的樣式,有以下代碼:

given $value {
    when "a match" {
        do-something();
    }
    when "another match" {
        do-something-else();
    }
    default {
        do-default-thing();
    }
}

這是在when語句中簡單的使用標量匹配的場景,更廣泛的實際狀況都是利用如正則表達式通常的複雜的實體等替代標量數據對輸入數據進行智能匹配。
同時參閱文章上面的智能匹配操做。

循環

while until

除了循環條件兩邊的括號如今是可選的,這些關鍵字幾乎沒有變化,可是若是要使用括號,必定沒關係跟着關鍵字,不然這會被看成普通的函數調用,綁定條件表達式到一個變量也稍微有點變化:

while (my $x = dostuff()) { ... }    # Perl 5
while dostuff() -> $x { ... }        # Perl 6

在 Perl 6中你能夠繼續使用my格式,可是它的做用域再也不位於語句塊的內部,而是外部。
注意對文件句柄按行讀取發生了變化。
在 Perl 5,這能夠利用鑽石運算符在while循環裏面完成,若是使用for替代while則會有一個常見的bug,由於for致使文件被一次性讀入,使程序的內存使用變的糟糕。
在 Perl 6,for語句是緩式的(lazy),因此咱們能夠在for循環裏面使用.lines方法逐行讀取文件:

while (<IN_FH>) { ... }        # Perl 5
for $IN_FH.lines { ... }    # Perl 6

for foreach

首先注意這有一個常見的對forforeach關鍵字的誤解,許多程序員認爲它們是把 C-風格for 和列表迭代方式區分開來,然而並非!實際上,它們是可互換的,Perl 5的編譯器經過查找後面的分號來決定解析成哪種循環。
C-風格的for循環如今使用loop關鍵字,其它都沒有變化,兩邊的括號是必須的:

for (my $i = 1;$i <= 10;$i++) { ... }    # Perl 5
loop (my $i = 1;$i <= 10;$i++) { ... }    # Perl 6

for或者foreach的循環迭代樣式如今統一叫作forforeach再也不是一個關鍵字,括號是可選的。
迭代變量,若是有的話,已經從列表的前部移動到列表的後面,變量以前還有加上箭頭運算符。
迭代變量,如今是詞法變量,my已經再也不須要並且不容許使用。
在 Perl 5裏,迭代變量是當前列表中元素的可讀寫別名。
在 Perl 6,這個別名默認是隻讀的(爲了安全),除非你將->改成<->。當翻譯的時候,檢查循環變量的使用來決定是否須要可讀寫。

for my $car (@cars) { ... }    # Perl 5,可讀寫
for @cars -> $car    { ... }    # Perl 6,只讀
for @cars <-> $car    { ... }    # Perl 6,可讀寫

若是使用默認的變量$_,可是又須要可讀寫,那麼須要使用<->並顯示指定變量爲$_

for (@cars)            { ... }        # Perl 5,默認變量
for @cars            { ... }        # Perl 6,$_ 是隻讀的
for @cars <-> $_     { ... }        # Perl 6,$_ 可讀寫
each

這是 Perl 6中和 Perl 5 while...each(%hash)或者while...each(@array)(遍歷數據結構的鍵或者索引和值)等同的用法:

while (my ($i, $v) = each(@array)) { ... }    # Perl 5
for @array.kv -> $i, $v { .... }            # Perl 6

while (my ($k, $v) = each(%hash)) { ... }    # Perl 5
for %hash.kv -> $k, $v { ... }                # Perl 6

流程控制

無變化的:

  • next

  • last

  • redo

continue

continue語句塊已經被去掉了,做爲替代,在循環體中使用NEXT語句塊:

# Perl 5
my $str = '';

for (1..5) {
    next if $_ % 2 == 1;
    $str .= $_;
}
continue {
    $str .= ':';
}

# Perl 6
my $str = '';
for 1..5 {
    next if $_ % 2 == 1;
    $str ~= $_;
    NEXT {
        $str ~= ':';
    }
}

函數

內建函數與裸露代碼塊

內建函數以前接受一個裸露的代碼塊,沒有逗號在其餘參數以前,如今須要在塊和參數之間插入一個逗號,好比mapgrep等等。

my @result = grep { $_ eq "bars" } @foo;    # Perl 5
my @result = grep { $_ eq "bars" }, @foo;    # Perl 6

delete

被轉換爲{}哈希下標運算符以及[]數組下標運算符的副詞。

my $deleted_value = delete $hash{$key};    # Perl 5
my $deleted_value = %hash{$key}:delete;    # Perl 6,使用 :delete 副詞

my $deleted_value = delete $array[$i];    # Perl 5
my $deleted_value = @array[$i]:delete;    # Perl 6,使用 :delete 副詞

exist

被轉換爲{}哈希下標運算符以及[]數組下標運算符的副詞。

say "element exists" if exists $hash{$key};    # Perl 5
say "element exists" if %hash{$key}:exists;    # Perl 6,使用 :exists 副詞

say "element exists" if exists $array[$i];    # Perl 5
say "element exists" if @array[$i]:exists;    # Perl 6,使用 :exists 副詞

正則表達式

由=~ !~變爲~~ !~~

在 Perl 5對變量的匹配和替換是使用=~正則綁定運算符完成的。
在 Perl 6中使用智能匹配運算符~~替代。

next if $line =~ /static/;        # Perl 5
next if $line ~~ /static/;        # Perl 6

next if $line !~ /dynamic/;        # Perl 5
next if $line !~~ /dynamic/;    # Perl 6

$line =~ s/abc/123/;            # Perl 5
$line ~~ s/abc/123/;            # Perl 6

一樣的,新的.match方法以及.subst方法能夠被使用。注意.subst是不可變操做,參見S05/Substitution

移動副詞

將全部的副詞的位置從尾部移動到了開始,這可能須要你爲普通的匹配好比/abc/添加可選的m

next if $line =~    /static/i;    # Perl 5
next if $line ~~ m:i/static/;    # Perl 6

增長 :P5 或者 :Perl5 副詞

若是實際的正則表達式比較複雜,你可能不想作修改直接使用,那麼就加上P5副詞吧。

next if $line =~    m/[aeiou]/;        # Perl 5
next if $line ~~ m:P5/[aeiou]/;        # Perl 6,使用 :P5 副詞
next if $line ~~    /<[aeiou]>/;    # Perl 6,新的風格

特殊的匹配語法一般屬於<>的語法

Perl 5的正則語法支持不少特殊的匹配語法,它們不會所有列在這裏,可是通常在斷言中做爲()的替代的是<>
對於字符類,這意味着:

Perl 5                                        Perl 6
[abc]                                        <[abc]>
[^abc]                                         <-[abc]>
[a-zA-Z]                                    <[a..zA..Z]>
[[:upper:]]                                    <:Upper>
[abc[:upper:]]                                <[abc]+:Upper>

對於環視(look-around)斷言:

Perl 5                                        Perl 6
(?=[abc])                                    <?[abc]>
(?=ar?bitray* pattern)                        <before ar?bitray* pattern>
(?!=[abc])                                    <![abc]>
(?!=ar?bitray* pattern)                        <!before ar?bitray* pattern>
(?<=ar?bitray* pattern)                        <after ar?bitray* pattern>
(?<!=ar?bitray* pattern)                    <!after ar?bitray* pattern>
    (跟<>語法無關,環視語法`/foo\Kbar/`變成了`/foo<(bar)>/`
(?(?{condition})yes-pattern|no-pattern)        [ <?{condition}> yes-pattern | no-pattern ]

長字符匹配(LTM)取代擇一

在 Perl 6的正則中,|用於LTM,也就是根據一組基於模糊匹配規則從結果中選擇一個最優的結果,而不是位置優先。
對於 Perl 5代碼最簡單解決方案就是使用||替代|
對於更多的規則,同時使用來自Blue Tigertranslate_regex.pl

編譯指示(Pragmas)

strict

嚴格模式如今是默認的。

warnings

警告如今默認是開啓的。
no warnings目前仍是NYI狀態,可是把語句放到quietly {}塊以內就能夠避免警告。

autodie

這個功能可讓程序在發生錯誤拋出異常,如今 Perl 6默認拋出異常,除非你顯式的測試返回值。

# Perl 5
open my $i_fh, '<', $input_path;    # 錯誤時保持沉默
use autodie;
open my $o_fh, '>', $output_path;    # 錯誤時拋出異常

# Perl 6
my $i_fh = open $input_path, :r;    # 錯誤時拋出異常
my $o_fh = open $output_path, :w;    # 錯誤時拋出異常

base

parent

如今use baseuse parent已經被 Perl 6中的is關鍵字取代,在類的聲明中。

# Perl 5
package Cat;
use base qw (Animal);

# Perl 6
class Cat is Animal;

bigint bignum bigrat

再也不相關。
Int如今是無限精度的,是Rat類型的分子(分母最大能夠是2**64,出於性能考慮以後會自動轉換爲Num類型)。若是你想使用無限精度分母的Rat,那麼FatRat顯然是最適合的。

constant

constant在 Perl 6用來變量聲明,這相似與my,不過變量會鎖定保持第一次初始化的值不變(在編譯時期求值)。
因此,將=>改成=,並加上一個 sigil。

use constant DEBUG => 0;    # Perl 5
constant    $DEBUG    = 0;    # Perl 6

use constant pi =>  4 * atan2(1, 1);    # Perl 5
# pi, e, i都是 Perl 6的內建變量

encoding

容許使用非ASCII或者非UTF8編碼編寫代碼。

integer

Perl的編譯指示,使用整數運算替代浮點。

lib

在編譯時期操做 @INC。

mro

再也不相關。
在 Perl 6中,方法調用如今使用 C3 方法調用順序。

utf8

再也不相關。
在 Perl 6中,源代碼將使用utf8編碼。

vars

在 Perl 5中被取代,參見vars
在翻譯到 Perl 6代碼以前,你可能須要重構你的代碼移除對use vars的使用。

命令行標記

參見S19/commandline
未變化的:

-c -e -h -I -n -p -S -T -v -V

-a

在Spec中沒有變化,可是在Rakudo中沒有實現。
如今你須要手動調用.split

-F

在Spec中沒有變化,可是在Rakudo中沒有實現。
如今你須要手動調用.split

-l

如今默認提供此行爲。

-M -m

只有-M還存在,還有,你們能夠再也不使用「no Module」語法了,-M的「no」模塊操做再也不可用。

-E

由於全部的特性都已經開啓,請使用小寫的-e

-d,-dt,-d:foo,-D 等

++BUG元語法替代。

-s

開關選項解析如今被MAIN子方法的參數列表替代。

# Perl 5
    #!/usr/bin/perl -s
    if ($xyz) { print "$xyz\n" }
./example.pl -xyz=5
5

# Perl 6
    sub MAIN(Int :$xyz) {
        say $xyz if $xyz.defined;
    }
perl6 example.p6 --xyz=6
6
perl6 example -xyz=6
6

-t

如今尚未指定。

-P -u -U -W -X

移除,參見S19/commandline

-w

如今默認開啓。

文件相關運算符

按行讀取文本文件到數組

在 Perl 5,讀取文本文件的行一般是這樣子:

open my $fh, '<', "file" or die "$!";
my @lines = <$fh>;
close $fh;

在 Perl 6,這簡化成了這樣:

my @lines = "file".IO.lines;

不要嘗試一次讀入一個文件,而後使用換行符分割,由於這會致使數組尾部含有一個空行,比你想象的多了一行(它實際更復雜一些)。好比:

# 初始化要讀的文件
spurt "test-file", q:to/END/;
first line
second line
third line
END
# 讀取
my @lines = "test-file".IO.slurp.split(/\n/);
say @lines.elems; # 輸出 4

捕獲可執行文件的標準輸出

鑑於 Perl 5你可能這麼作:

my $arg = 'Hello';
my $captured = \`echo \Q$arg\E\`; # 注意反引號\`
my $captured = qx(echo \Q$arg\E);

或者使用String::ShellQuote(由於\Q...\E不是徹底正確的):

my $arg = shell_quote 'Hello';
my $captured = 'echo $arg';
my $captured = qx(echo $arg);

在 Perl 6中你可能不想經過shell運行命令:

my $arg = 'Hello';
my $captured = run('echo', $arg, :out).out.slurp-rest;
my $captured = run(«echo "$arg"», :out).out.slurp-rest;

若是你想也可使用shell:

my $arg = 'Hello';
my $captured = shell("echo $arg", :out).out.slurp-rest;
my $captured = qqx{echo $arg};

可是小心這種狀況徹底沒有保護,run不使用shell執行命令,因此不須要對參數進行轉義(直接進行傳遞)。若是你使用shell或者qqx,那麼全部東西都會做爲一個長長的字符串傳給shell,除非你當心的驗證你的參數,頗有可能由於這樣的代碼引入shell注入漏洞。

環境變量

perl模塊路徑

在 Perl 5中能夠指定 Perl 模塊的額外的搜索路徑的一個環境變量是PERL5LIB

$ PERL5LIB="/some/module/lib" perl program.pl

在 Perl 6中也相似,僅僅須要改變一個數字,正如你想的那樣,你只需使用PERL6LIB

$ PERL6LIB="/some/module/lib" perl6 program.p6

就 Perl 5來講,若是你不指定PERL5LIB,你須要使用use lib編譯指示來指定庫的路徑:

use lib '/some/module/lib'

注意PERL6LIB在 Perl 6中更多的是給開發者提供便利(與 Perl 5中的PERL5LIB相對應),模塊的用戶不要使用由於將來它可能被刪除,這是由於 Perl 6的模塊加載沒有直接兼容操做系統的路徑。

雜項

'0'是 True

不像 Perl 5,一個只包含('0')的字符串是 True,做爲 Perl 6的核心類型,它有着更多的意義,這意味着常見的模式:

... if defined $x and length $x;    # 或者現代 Perl 的寫法 length($x)

在 Perl6裏面變的更爲簡化:

... if $x;

dump

被移除。
Perl 6的設計容許自動的保存加載編譯的字節碼。
Rakudo目前只支持模塊。

導入模塊的函數

在 Perl 5你能夠像這樣有選擇性的導入一個給定模塊的函數:

use ModuleName qw{foo bar baz};

在 Perl 6,一個想要被導出的函數須要對相關的方法使用is export,全部使用is export的方法都會被導出,所以,下面的模塊Bar導出了方法foobar,沒有導出baz

unit module Bar;
sub foo($a) is export { say "foo $a" }
sub bar($b) is export { say "bar $b" }
sub baz($z) { say "baz $z" }

使用模塊時,簡單的use Bar便可,如今函數foobar都是可用的:

use Bar;
foo(1);    # 輸出 "foo 1"
bar(2);    # 輸出 "bar 2"

若是你嘗試調用baz函數,會在編譯時報出「未定義的例程」錯誤。
因此,如何像 Perl 5那樣可選擇性的導入一個模塊的函數呢?支持這個你須要在模塊中定義EXPORT方法來指定導出和刪除module Bar的聲明(注意在Synopsis 11中並無module語句,然而它能夠工做) 。
模塊Bar如今僅僅是一個叫作Bar.pm的文件並含有如下內容:

use v6;

sub EXPORT(*@import-list) {
    my %exportable-subs = '&foo' => &foo, '&bar' => &bar,;
    my %subs-to-export;

    for @import-list -> $sub-name {
        if grep $sub-name, %exportable-subs.keys {
            %subs-to-export{$sub-name} = %exportable-subs{$sub-name};
        }
    }

    return %subs-to-export;
}
sub foo($a) { say "foo $a" }
sub bar($b) { say "bar $b" }
sub baz($z) { say "baz $z" }

注意如今方法已再也不使用is export顯式的導出,咱們定義了一個EXPORT方法,它指定了模塊能夠被導出的方法,而且生成一個包含實際被導出的方法的哈希,@import-list是調用代碼中使用set語句設置的,這容許咱們可選擇性的導出模塊中可導出的方法。
因此,爲了只導出foo例程,咱們能夠這麼使用:

use Bar <foo>;
foo(1);    # 輸出 "foo 1"

如今咱們發現即便bar是可導出的,若是咱們沒有顯式的導出它,它就不會可用,所以下面的代碼在編譯時會引發「未定義的例程」錯誤:

use Bar <foo>;
foo(1);
bar(5);       # 報錯 "Undeclared routine: bar used at line 3"

然而,咱們能夠這樣:

use Bar <foo bar>;
foo(1);    # 輸出 "foo 1"
bar(5);    # 輸出 "bar 5"

注意,baz依然是不可導出的即便使用use指定:

use Bar <foo bar baz>;
baz(3);       # 報錯 "Undeclared routine: baz used at line 2"

爲了使這個能正常工做,顯然須要跨越許多的障礙,在使用標準use的狀況下,經過使用is export指定某一個函數是導出的,Perl 6會自動以正確的方式建立EXPORT方法,因此你應該仔細的考慮建立一個本身的EXPORT方法是否值得。

核心模塊

Data::Dumper

在 Perl 5,Data::Dumper模塊被用來序列化,還有程序員調試的時候用來查看程序數據結構的內容。
在 Perl 6中,這個任務徹底被存在於每個對象的.perl方法替代。

# 給定
my @array_of_hashes = (
    {NAME => 'apple', type => 'fruit'},
    {NAME => 'cabbage', type => 'no, plese no'},
);

# Perl 5
use Data::Dumper;
$Data::Dumper::Useqq = 1;
print Dumper \@array_of_hashes;    # 注意反斜槓

# Perl 6
say @array_of_hashes.perl;    # .perl會做用在數組而不是引用上面

在 Perl 5,Data::Dumper有着更復雜的可選的調用約定,它支持對變量命名。
在 Perl 6,將一個冒號放在變量的 sigil 前面轉換它爲 Pair,Pair 的鍵是變量的名字,值是變量的值。

#給定
my ($foo, $bar) = (42, 44);
my @baz = (16, 32, 64, 'Hike!');

# Perl 5
use Data::Dumper;
print Data::Dumper->Dump(
    [$foo, $bar, \@baz],
    [qw(foo bar *baz )],
);

# 輸出
    $foo = 42;
    $bar = 44;
    @baz = (
            16,
            32,
            64,
            'Hike!'
        );

# Perl 6
say [ :$foo, :$bar, :@baz ].perl;

# 輸出
    ["foo" => 42, "bar" => 44, "baz" => [16, 32, 64, "Hike!"]]

Getopt::Long

開關選項解析如今被MAIN子方法的參數列表替代。

# Perl 5
use 5.010;
use Getopt::Long;
GetOptions(
    'length=i'    =>    \(my $length = 24),            # 數值
    'file=s'    =>    \(my $data = 'file.data'),    # 字符串
    'verbose'    =>    \(my $verbose),                # 標誌
) or die;
say $length;
say $data;
say 'Verbosity', ($verbose ? 'on' : 'off') if defined $verbose;

perl example.pl
    24
    file.data
perl example.pl --file=foo --length=42 --verbose
    42
    foo
    Verbosity on

perl example.pl --length=abc
    Value "abc" invalid for option length (number expected)
    Died at c.pl line 3.

# Perl 6
sub MAIN (Int :$length = 24, :file($data) = 'file.data', Bool :$verbose) {
    say $length    if $length.defined;
    say $data    if $data.defined;
    say "Verbosity", ($verbose ?? 'on' !! 'off');
}
perl6 example.p6
    24
    file.dat
    Verbosity off
perl6 example.p6 --file=foo --length=42 --verbose
    42
    foo
    Verbosity on
perl6 example.p6 --length=abc
    Usage:
        example.p6 [--length=<Int>] [--file=<Any>] [--verbose]

注意 Perl 6會在命令行解析出錯時自動生成一個完整的用法信息。

自動化翻譯

一個快速的將 Perl 5代碼翻譯爲 Perl 6代碼的途徑就是經過自動化翻譯。
注意:這些翻譯器都尚未完成。

Blue Tiger

本項目的目致力於自動現代化 Perl 代碼,它沒有一個 web 前端,因此必須本地安裝使用,它還含有一個單獨的程序用來將 Perl 5的正則轉換爲 Perl 6的版本。
https://github.com/Util/Blue_Tiger/

Perlito

在線翻譯器。
本項目是一套 Perl 跨平臺編譯器,包含 Perl 5到 Perl 6的翻譯,它有一個 web 前端,因此能夠在不安裝的前提下使用,它目前只支持 Perl 5語法的一個子集。
http://www.perlito.org/perlito/perlito5to6.html

MAD

Larry Wall 本身用來翻譯 Perl 5到 Perl 6的代碼已經太老了,在目前的 Perl 5版本中已經不可用了。
MAD(Misc Attribute Definition)是一個經過源碼構建 Perl 的時候可用的配置選項, perl\執行程序分析並翻譯你的 Perl 代碼到 op-tree,經過遍歷 op-tree執行你的程序。一般,這些分析的細節會在處理的時候丟掉,當MAD開啓的時候,`perl`執行程序會把這些細節保存成XML文件,而後MAX解析器即可以讀取它並進一步處理成 Perl 6的代碼。
爲了進行你的MAD實驗,請前去 #perl6 頻道請教最適合的 Perl 5 版本。

Perl-ToPerl6

Jeff Goff的圍繞 Perl::Critic 框架的用於 Perl 5的模塊 Perl::ToPerl6 ,目標是最最小的修改並將 Perl 5的代碼轉換成可編譯的 Perl 6代碼,代碼的轉換器是可配置和插件化的,你能夠經過它建立本身的轉換器,根據你的需求自定義存在的轉換器。你能夠從CPAN上面獲取最新的版本,或者 follow 發佈在 GitHub 的工程,在線轉換器可能在某一天會可用。

翻譯知識的其餘來源

相關文章
相關標籤/搜索