diff options
Diffstat (limited to 'zh-tw')
-rw-r--r-- | zh-tw/bash-tw.html.markdown | 2 | ||||
-rw-r--r-- | zh-tw/dart-tw.html.markdown | 566 | ||||
-rw-r--r-- | zh-tw/elixir-tw.html.markdown | 16 | ||||
-rw-r--r-- | zh-tw/perl-tw.html.markdown | 328 | ||||
-rw-r--r-- | zh-tw/pythonlegacy-tw.html.markdown (renamed from zh-tw/python-tw.html.markdown) | 6 |
5 files changed, 906 insertions, 12 deletions
diff --git a/zh-tw/bash-tw.html.markdown b/zh-tw/bash-tw.html.markdown index 78b39f2d..5136d513 100644 --- a/zh-tw/bash-tw.html.markdown +++ b/zh-tw/bash-tw.html.markdown @@ -23,7 +23,7 @@ filename: LearnBash-tw.sh lang: zh-tw --- -Bash 是一個爲 GNU 計劃編寫的 Unix shell,是 Linux 和 Mac OS X 下預設的 shell。 +Bash 是一個爲 GNU 計劃編寫的 Unix shell,是 Linux 和 macOS 下預設的 shell。 以下大多數例子可以作爲腳本的一部分運行,也可直接在 shell 下互動執行。 [更多資訊](http://www.gnu.org/software/bash/manual/bashref.html) diff --git a/zh-tw/dart-tw.html.markdown b/zh-tw/dart-tw.html.markdown new file mode 100644 index 00000000..5a9241c2 --- /dev/null +++ b/zh-tw/dart-tw.html.markdown @@ -0,0 +1,566 @@ +--- +language: dart +lang: zh-tw +filename: learndart-tw.dart +contributors: + - ["Joao Pedrosa", "https://github.com/jpedrosa/"] +translators: + - ["Bob Lu", "https://github.com/LuPoYi/"] +--- + +Dart 是程式語言領域的新人。 +它借鑒了許多其他主流語言,並且不會偏離它的兄弟語言 JavaScript 太多。 +就像 JavaScript 一樣,Dart 的目標是提供良好的瀏覽器整合性。 + +Dart 最有爭議的特性必然是它的可選類型。 + +```javascript +import "dart:collection"; +import "dart:math" as DM; + +// 歡迎進入15分鐘的 Dart 學習。 http://www.dartlang.org/ +// 這是一個可實際執行的範例。你可以用 Dart 執行它 +// 或者線上執行! 可以把程式碼複製/貼上到這個網站。 http://try.dartlang.org/ + +// 函數宣告和方法宣告看起來一樣。 +// 函數宣告可以是巢狀的。宣告使用這種 name() {} 的形式, +// 或者 name() => 單行表示式; 的形式。 +// 右箭頭的宣告形式會直接地返回表示式的結果。 +example1() { + example1nested1() { + example1nested2() => print("Example1 nested 1 nested 2"); + example1nested2(); + } + example1nested1(); +} + +// 匿名函數沒有函數名。 +example2() { + example2nested1(fn) { + fn(); + } + example2nested1(() => print("Example2 nested 1")); +} + +// 當宣告函數類型的參數的時候,宣告中可以包含 +// 函數參數需要的參數,指定所需的參數名即可。 +example3() { + example3nested1(fn(informSomething)) { + fn("Example3 nested 1"); + } + example3planB(fn) { // 或者不宣告函數參數的參數 + fn("Example3 plan B"); + } + example3nested1((s) => print(s)); + example3planB((s) => print(s)); +} + +// 函數有可以訪問到外層變數的閉包。 +var example4Something = "Example4 nested 1"; +example4() { + example4nested1(fn(informSomething)) { + fn(example4Something); + } + example4nested1((s) => print(s)); +} + +// 下面這個包含 sayIt 方法的類別宣告,同樣有一個可以訪問外層變數的閉包, +// 就像前面的函數一樣。 +var example5method = "Example5 sayIt"; +class Example5Class { + sayIt() { + print(example5method); + } +} +example5() { + // 創建一個 Example5Class 類的匿名實例, + // 並呼叫它的 sayIt 方法。 + new Example5Class().sayIt(); +} + +// 類別的宣告使用這種形式 class name { [classBody] }. +// classBody 中可以包含實例方法和變數, +// 還可以包含類別方法和變數。 +class Example6Class { + var example6InstanceVariable = "Example6 instance variable"; + sayIt() { + print(example6InstanceVariable); + } +} +example6() { + new Example6Class().sayIt(); +} + +// 類別方法和變數使用 static 宣告。 +class Example7Class { + static var example7ClassVariable = "Example7 class variable"; + static sayItFromClass() { + print(example7ClassVariable); + } + sayItFromInstance() { + print(example7ClassVariable); + } +} +example7() { + Example7Class.sayItFromClass(); + new Example7Class().sayItFromInstance(); +} + +// 定數非常方便,但是對於在函數/方法的外層的定數有一個限制, +// 類別的外層或外面的定數必須是常數。 +// 字串和數字預設是常數。 +// 但是 array 和 map 不是。他們需要用 "const" 宣告為常數。 +var example8Array = const ["Example8 const array"], + example8Map = const {"someKey": "Example8 const map"}; +example8() { + print(example8Array[0]); + print(example8Map["someKey"]); +} + +// Dart 中的迴圈使用標準的 for () {} 或 while () {} 的形式, +// 以及更加現代的 for (.. in ..) {} 的形式, 或者 +// 以 forEach 開頭並具有許多特性支援函數回呼的形式。 +var example9Array = const ["a", "b"]; +example9() { + for (var i = 0; i < example9Array.length; i++) { + print("Example9 for loop '${example9Array[i]}'"); + } + var i = 0; + while (i < example9Array.length) { + print("Example9 while loop '${example9Array[i]}'"); + i++; + } + for (var e in example9Array) { + print("Example9 for-in loop '${e}'"); + } + example9Array.forEach((e) => print("Example9 forEach loop '${e}'")); +} + +// 透過迴圈遍歷字串中的每個字元或者取出其子字串。 +var example10S = "ab"; +example10() { + for (var i = 0; i < example10S.length; i++) { + print("Example10 String character loop '${example10S[i]}'"); + } + for (var i = 0; i < example10S.length; i++) { + print("Example10 substring loop '${example10S.substring(i, i + 1)}'"); + } +} + +// 支援兩種數字格式 int 和 double。 +example11() { + var i = 1 + 320, d = 3.2 + 0.01; + print("Example11 int ${i}"); + print("Example11 double ${d}"); +} + +// DateTime 提供了日期/時間的方法。 +example12() { + var now = new DateTime.now(); + print("Example12 now '${now}'"); + now = now.add(new Duration(days: 1)); + print("Example12 tomorrow '${now}'"); +} + +// 支援正規表達式。 +example13() { + var s1 = "some string", s2 = "some", re = new RegExp("^s.+?g\$"); + match(s) { + if (re.hasMatch(s)) { + print("Example13 regexp matches '${s}'"); + } else { + print("Example13 regexp doesn't match '${s}'"); + } + } + match(s1); + match(s2); +} + +// 布林運算式支持隱式轉換以及動態類型 +example14() { + var a = true; + if (a) { + print("Example14 true, a is $a"); + } + a = null; + if (a) { + print("Example14 true, a is $a"); + } else { + print("Example14 false, a is $a"); // 執行到這裡 + } + +// 動態類型的null可以轉換成bool型 + var b; // b是動態類型 + b = "abc"; + try { + if (b) { + print("Example14 true, b is $b"); + } else { + print("Example14 false, b is $b"); + } + } catch (e) { + print("Example14 error, b is $b"); // 這段程式碼可以執行但是會報錯 + } + b = null; + if (b) { + print("Example14 true, b is $b"); + } else { + print("Example14 false, b is $b"); // 執行到這裡 + } + + // 靜態類型的null不能轉換成bool型 + var c = "abc"; + c = null; + // 編譯出錯 + // if (c) { + // print("Example14 true, c is $c"); + // } else { + // print("Example14 false, c is $c"); + // } +} + +// try/catch/finally 和 throw 語句用於例外處理。 +// throw 語句可以使用任何物件作為參數。 +example15() { + try { + try { + throw "Some unexpected error."; + } catch (e) { + print("Example15 an exception: '${e}'"); + throw e; // Re-throw + } + } catch (e) { + print("Example15 catch exception being re-thrown: '${e}'"); + } finally { + print("Example15 Still run finally"); + } +} + +// 想要有效地動態創建長字串, +// 應該使用 StringBuffer。或者 join 一個字串的陣列。 +example16() { + var sb = new StringBuffer(), a = ["a", "b", "c", "d"], e; + for (e in a) { sb.write(e); } + print("Example16 dynamic string created with " + "StringBuffer '${sb.toString()}'"); + print("Example16 join string array '${a.join()}'"); +} + +// 字串連接只需讓相鄰的字串相連, +// 不需要額外的操作運算符號。 +example17() { + print("Example17 " + "concatenate " + "strings " + "just like that"); +} + +// 字串使用單引號或雙引號做分隔,二者並沒有實際的差異。 +// 這種靈活性可以很好地避免內容中需要轉義換行的情況。 +// 例如,字串內容裡的 HTML 屬性使用了雙引號。 +example18() { + print('Example18 <a href="etc">' + "Don't can't I'm Etc" + '</a>'); +} + +// 用三個單引號或三個雙引號表示的字串 +// 可以跨越多行,並且包含換行。 +example19() { + print('''Example19 <a href="etc"> +Example19 Don't can't I'm Etc +Example19 </a>'''); +} + +// 字串可以使用 $ 符號插入內容。 +// 使用 $ { [expression] } 的形式,表示式的值會被插入到字串中。 +// $ 跟著一個變數名會插入變數的值。 +// 如果要在字符串中插入 $ ,可以使用 \$ 的轉義形式取代。 +example20() { + var s1 = "'\${s}'", s2 = "'\$s'"; + print("Example20 \$ interpolation ${s1} or $s2 works."); +} + +// 可選類型允許作為 API 的標註,並且可以輔助 IDE, +// 這樣 IDE 可以更好地提供重構、自動完成和錯誤檢測功能。 +// 目前為止我們還沒有宣告任何類型,並且程式可以執行。 +// 事實上,類型在執行時會被忽略。 +// 類型甚至可以是錯的,並且程式依然可以執行, +// 好像和類型完全無關一樣。 +// 有一個執行時參數可以讓程式進入檢查模式,它會在執行時檢查類型錯誤。 +// 這在開發時很有用,但是由於增加了額外的檢查會使程式變慢, +// 因此應該避免在部署時使用。 +class Example21 { + List<String> _names; + Example21() { + _names = ["a", "b"]; + } + List<String> get names => _names; + set names(List<String> list) { + _names = list; + } + int get length => _names.length; + void add(String name) { + _names.add(name); + } +} + +void example21() { + Example21 o = new Example21(); + o.add("c"); + print("Example21 names '${o.names}' and length '${o.length}'"); + o.names = ["d", "e"]; + print("Example21 names '${o.names}' and length '${o.length}'"); +} + +// 類型的繼承形式是 class name extends AnotherClassName {} 。 +class Example22A { + var _name = "Some Name!"; + get name => _name; +} +class Example22B extends Example22A {} +example22() { + var o = new Example22B(); + print("Example22 class inheritance '${o.name}'"); +} + +// 類型也可以使用 mixin 的形式 : +// class name extends SomeClass with AnotherClassName {}. +// 必需繼承某個類型才能 mixin 另一個類型。 +// 當前 mixin 的模板類型不能有建構子。 +// Mixin 主要是用來和輔助的類型共享方法的, +// 這樣單一繼承就不會影響程式碼重覆使用。 +// Mixin 宣告在類型定義的 "with" 後面。 +class Example23A {} +class Example23Utils { + addTwo(n1, n2) { + return n1 + n2; + } +} +class Example23B extends Example23A with Example23Utils { + addThree(n1, n2, n3) { + return addTwo(n1, n2) + n3; + } +} +example23() { + var o = new Example23B(), r1 = o.addThree(1, 2, 3), + r2 = o.addTwo(1, 2); + print("Example23 addThree(1, 2, 3) results in '${r1}'"); + print("Example23 addTwo(1, 2) results in '${r2}'"); +} + +// 類型的建構子和類型名相同,形式為 +// SomeClass() : super() {}, 其中 ": super()" 的部分是可選的, +// 它用來傳遞參數給父類型的建構子。 +class Example24A { + var _value; + Example24A({value: "someValue"}) { + _value = value; + } + get value => _value; +} +class Example24B extends Example24A { + Example24B({value: "someOtherValue"}) : super(value: value); +} +example24() { + var o1 = new Example24B(), + o2 = new Example24B(value: "evenMore"); + print("Example24 calling super during constructor '${o1.value}'"); + print("Example24 calling super during constructor '${o2.value}'"); +} + +// 對於簡單的類型,有一種設置構造函數參數的快捷方式。 +// 只需要使用 this.parameterName 的前綴, +// 它就會把參數設置為同名的實例變數。 +class Example25 { + var value, anotherValue; + Example25({this.value, this.anotherValue}); +} +example25() { + var o = new Example25(value: "a", anotherValue: "b"); + print("Example25 shortcut for constructor '${o.value}' and " + "'${o.anotherValue}'"); +} + +// 可以在大括號 {} 中宣告命名參數。 +// 大括號 {} 中宣告的參數的順序是隨意的。 +// 在中括號 [] 中宣告的參數也是可選的。 +example26() { + var _name, _surname, _email; + setConfig1({name, surname}) { + _name = name; + _surname = surname; + } + setConfig2(name, [surname, email]) { + _name = name; + _surname = surname; + _email = email; + } + setConfig1(surname: "Doe", name: "John"); + print("Example26 name '${_name}', surname '${_surname}', " + "email '${_email}'"); + setConfig2("Mary", "Jane"); + print("Example26 name '${_name}', surname '${_surname}', " + "email '${_email}'"); +} + +// 使用 final 宣告的變數只能被設置一次。 +// 在類型裡面,final 實例變數可以通過常數的建構子參數設置。 +class Example27 { + final color1, color2; + // 更靈活一點的方法是在冒號 : 後面設置 final 實例變數。 + Example27({this.color1, color2}) : color2 = color2; +} +example27() { + final color = "orange", o = new Example27(color1: "lilac", color2: "white"); + print("Example27 color is '${color}'"); + print("Example27 color is '${o.color1}' and '${o.color2}'"); +} + +// 要導入一個函式庫,使用 import "libraryPath" 的形式,或者如果要導入的是 +// 核心庫使用 import "dart:libraryName" 。還有一個稱為 "pub" 的套件管理工具, +// 它使用 import "package:packageName" 的約定形式。 +// 看下這個文件頂部的 import "dart:collection"; 語法。 +// 導入語句必需在其它程式碼宣告之前出現。 IterableBase 來自於 dart:collection 。 +class Example28 extends IterableBase { + var names; + Example28() { + names = ["a", "b"]; + } + get iterator => names.iterator; +} +example28() { + var o = new Example28(); + o.forEach((name) => print("Example28 '${name}'")); +} + +// 對於控制流程,我們有: +// * 必需帶 break 的標準 switch 語法 +// * if-else 和三元運算子 ..?..:.. +// * 閉包和匿名函數 +// * break, continue 和 return 語法 +example29() { + var v = true ? 30 : 60; + switch (v) { + case 30: + print("Example29 switch statement"); + break; + } + if (v < 30) { + } else if (v > 30) { + } else { + print("Example29 if-else statement"); + } + callItForMe(fn()) { + return fn(); + } + rand() { + v = new DM.Random().nextInt(50); + return v; + } + while (true) { + print("Example29 callItForMe(rand) '${callItForMe(rand)}'"); + if (v != 30) { + break; + } else { + continue; + } + // 不會到這裡。 + } +} + +// 解析 int,把 double 轉成 int,或者使用 ~/ 運算符號在除法計算時僅保留整數位。 +// 讓我們也來場猜數遊戲吧。 +example30() { + var gn, + tooHigh = false, + n, + n2 = (2.0).toInt(), + top = int.parse("123") ~/ n2, + bottom = 0; + top = top ~/ 6; + gn = new DM.Random().nextInt(top + 1); // +1 because nextInt top is exclusive + print("Example30 Guess a number between 0 and ${top}"); + guessNumber(i) { + if (n == gn) { + print("Example30 Guessed right! The number is ${gn}"); + } else { + tooHigh = n > gn; + print("Example30 Number ${n} is too " + "${tooHigh ? 'high' : 'low'}. Try again"); + } + return n == gn; + } + + n = (top - bottom) ~/ 2; + while (!guessNumber(n)) { + if (tooHigh) { + top = n - 1; + } else { + bottom = n + 1; + } + n = bottom + ((top - bottom) ~/ 2); + } +} + +// 選填位置參數: +// 參數定義使用方括號 [ ],傳入參數是選填的。 +example31() { + findVolume31(int length, int breath, [int height]) { + print('length = $length, breath = $breath, height = $height'); + } + + findVolume31(10,20,30); // 可執行 + findVolume31(10,20); // 也可執行 +} + +// 選填命名參數: +// 參數定義使用大括號 { }, 傳入參數是選填的。 +// 必須傳入參數名稱及參數值,並以 : 分隔 +// 大括號的順序沒有差別 +// 這種類型參數可以幫我們避免多個參數傳入時造成混淆。 +example32() { + findVolume32(int length, int breath, {int height}) { + print('length = $length, breath = $breath, height = $height'); + } + + findVolume32(10,20,height:30); // 可執行 & 參數名稱在這邊有傳入 + findVolume32(10,20); // 也可執行 +} + +// 選填預設參數: +// 與選填命名參數相同,此外,我們為此參數定義的預設值 +// 如果沒有傳入值,就使用預設值 +example33() { + findVolume33(int length, int breath, {int height=10}) { + print('length = $length, breath = $breath, height = $height'); + } + + findVolume33(10,20,height:30); // 可執行 + findVolume33(10,20); // 可執行 +} + +// 程式的唯一入口點是 main 函式。 +// 在程式開始執行 main 函式之前,不會執行任何外部程式碼。 +// 這樣有助於更快加載甚至是延遲加載程式啟動時所需要的部分; +main() { + print("Learn Dart in 15 minutes!"); + [ + example1, example2, example3, example4, example5, + example6, example7, example8, example9, example10, + example11, example12, example13, example14, example15, + example16, example17, example18, example19, example20, + example21, example22, example23, example24, example25, + example26, example27, example28, example29, + example30 // 增加此註解可阻止dart formatter把所有項目都換行 + ].forEach((ef) => ef()); +} + +``` + +## 延伸閱讀 + +Dart 有一個綜合性網站。它涵蓋了 API 參考、入門教學、文章以及更多, +還包括一個有用的線上試用 Dart 頁面。 +* [https://www.dartlang.org](https://www.dartlang.org) +* [https://try.dartlang.org](https://try.dartlang.org) diff --git a/zh-tw/elixir-tw.html.markdown b/zh-tw/elixir-tw.html.markdown index c15f90c1..3dba95b3 100644 --- a/zh-tw/elixir-tw.html.markdown +++ b/zh-tw/elixir-tw.html.markdown @@ -1,5 +1,5 @@ --- -language: elixir +language: Elixir contributors: - ["Joao Marques", "http://github.com/mrshankly"] - ["Dzianis Dashkevich", "https://github.com/dskecse"] @@ -19,10 +19,10 @@ Elixir 是一門建構在 Erlang 虛擬機上的現代函數式語言。它完 # 沒有多行註解的功能 # 但你可以連續使用多個單行 -# 用 `iex` 來進入 elixir shell +# 用 `iex` 來進入 Elixir shell # 用 `elixirc` 來編譯你的模組 -# 如果你已成功安裝 elixir 的話,這兩個命令應已在你的 path 下。 +# 如果你已成功安裝 Elixir 的話,這兩個命令應已在你的 path 下。 ## --------------------------- ## -- 基本型別 @@ -50,7 +50,7 @@ elem({1, 2, 3}, 0) #=> 1 head #=> 1 tail #=> [2,3] -# 在 elixir 中,就如同 Erlang 裡一樣,`=` 代表的是模式比對,而非指派。 +# 在 Elixir 中,就如同 Erlang 裡一樣,`=` 代表的是模式比對,而非指派。 # # 這代表將使用左手邊的模式 (pattern) 去與右手邊的值進行比對。 # @@ -80,7 +80,7 @@ string. <<?a, ?b, ?c>> #=> "abc" [?a, ?b, ?c] #=> 'abc' -# `?a` 在 elixir 中會回傳字母 `a` 的 ASCII 整數 +# `?a` 在 Elixir 中會回傳字母 `a` 的 ASCII 整數 ?a #=> 97 # 用 `++` 來合併串列,而合併二進位則要用 `<>` @@ -105,7 +105,7 @@ lower..upper = 1..10 # 可以對 range 進行模式比對 5 * 2 #=> 10 10 / 2 #=> 5.0 -# 在 elixir 中, `/` 運算元永遠回傳浮點數。 +# 在 Elixir 中, `/` 運算元永遠回傳浮點數。 # 若需要回傳整數的除法,用 `div` div(10, 2) #=> 5 @@ -290,7 +290,7 @@ Geometry.area({:circle, 3}) #=> 28.25999999999999801048 # Geometry.area({:circle, "not_a_number"}) #=> ** (FunctionClauseError) no function clause matching in Geometry.area/1 -# 由於不可變特性 (immutability),遞迴在 elixir 中扮演重要的角色。 +# 由於不可變特性 (immutability),遞迴在 Elixir 中扮演重要的角色。 defmodule Recursion do def sum_list([head | tail], acc) do sum_list(tail, acc + head) @@ -356,7 +356,7 @@ end ## -- 平行處理 ## --------------------------- -# Elixir 依靠 actor 模式來進行平行處理。在 elixir 中要寫出平行處理程式, +# Elixir 依靠 actor 模式來進行平行處理。在 Elixir 中要寫出平行處理程式, # 只需要三個基本要素:建立行程,發送訊息及接收訊息。 # 我們用 `spawn` 函式來建立行程,它接收一個函式當參數。 diff --git a/zh-tw/perl-tw.html.markdown b/zh-tw/perl-tw.html.markdown new file mode 100644 index 00000000..55876e2a --- /dev/null +++ b/zh-tw/perl-tw.html.markdown @@ -0,0 +1,328 @@ +--- +name: perl +category: language +language: perl +filename: learnperl-tw.pl +contributors: + - ["Korjavin Ivan", "http://github.com/korjavin"] + - ["Dan Book", "http://github.com/Grinnz"] +translators: + - ["Kang-min Liu", "https://gugod.org"] + - ["Shih-Kai Chiu", "https://twitter.com/zard1989"] +lang: zh-tw +--- + +Perl 5 是一款強大且功能豐富的程式語言,已經持續發展超過 25 年。 + +從大型主機到行動裝置,Perl 5 能在上百種平台執行,適合快速打造產品原型,也適合大 +型專案開發。 + +```perl +# 註解列皆以井字號為開頭 + +#### 嚴謹度 + +use strict; +use warnings; + +# 所有的 perl 程式檔案都應當包含此兩列程式碼。在如變數名稱有拼寫錯誤之時, +# strict 能使編譯過程失敗。而對於像是將未定義值接到字串中等等易犯之錯誤, +# warnings 則能提供適當的警告訊息。 + +#### Perl 變數與其型別 + +# 變數的開頭皆為一印記(sigil),是為一符號,用以標示其型別。 +# 變數名稱唯有以字母或底線開頭,後接字母、數字、底線若干,方為有效。 + +### 在 Perl 語言中,主要的變數型別有三種:$純量、@陣列、%雜湊。 + +## 純量 +# 一個純量變數,只能裝一個值: +my $animal = "camel"; +my $answer = 42; +my $display = "You have $answer ${animal}s.\n"; + +# 純量值可為字串、整數、浮點數。Perl 會自動地在需要之時進行轉換。 + +# 以單引號括住的字串內容與其字面之值完全相同。而以雙引號括住的字串, +# 其中則能內插變數與像是這種表示換列字符 "\n" 的控制碼。 + +## 陣列 +# 一個陣列,可以裝下很多值: +my @animals = ("camel", "llama", "owl"); +my @numbers = (23, 42, 69); +my @mixed = ("camel", 42, 1.23); + +# 陣列元素的存取,需要角括號。前方的印記為 $ 符號,表示只取一個值。 +my $second = $animals[1]; + +# 欲知陣列之大小,在純量語境之下使用陣列便可。例如,將陣列裝到一個純量變數中。 +# 又或者是使用 "scalar" 算符。 + +my $num_animals = @animals; +print "Number of numbers: ", scalar(@numbers), "\n"; + +# 陣列也能夠被安插在雙引號字串之內。各內容元素間隔,預設是一個空白字符。 + +print "We have these numbers: @numbers\n"; + +# 雙引號字串中,若有像電子郵件地址的部分,會被視為是在內插某個陣列的內容物。 +# 請稍加留意。 + +my @example = ('secret', 'array'); +my $oops_email = "foo@example.com"; # 'foosecret array.com' +my $ok_email = 'foo@example.com'; + +## 雜湊 +# 一個雜湊,能裝下許多對的鍵與值: + +my %fruit_color = ("apple", "red", "banana", "yellow"); + +# 善用空白與 "=>" 算符,就能將其排得得好看一些: + +my %fruit_color = ( + apple => "red", + banana => "yellow", +); + +# 雜湊元素的存取,需要大括號。前方的印記仍為 $ 符號,表示只取一個值。 +my $color = $fruit_color{apple}; + +# 以 "keys" 與 "values" 兩個函數,則可一次取得雜湊中的所有鍵、所有值。 +my @fruits = keys %fruit_color; +my @colors = values %fruit_color; + +# 關於純量、陣列、雜湊,在 perldata 文件之中,有更完整的描述。 +# (perldoc perldata) + +#### 參照 + +# 以參照能組出結構更為複雜的資料型別。 +# 像是在陣列中放入雜湊、或是在雜湊裡放入陣列的雜湊。 + +my $array_ref = \@array; +my $hash_ref = \%hash; +my @array_of_arrays = (\@array1, \@array2, \@array3); + +# 匿名陣列與匿名雜湊也是參照 + +my $fruits = ["apple", "banana"]; +my $colors = {apple => "red", banana => "yellow"}; + +# 在參照之前補上適當的印記,是為解參照。 + +my @fruits_array = @$fruits; +my %colors_hash = %$colors; + +# 以箭頭算符,便可在解參照同時存取其中一值。 + +my $first = $array_ref->[0]; +my $value = $hash_ref->{banana}; + +# 欲深入了解參照,詳見 perlreftut 與 perlref 兩份文件 + +#### 條件結構與迴圈結構 + +# Perl 語言中亦具備常見的條件結講與迴圈結構。 + +if ($var) { + ... +} elsif ($var eq 'bar') { + ... +} else { + ... +} + +unless (condition) { + ... +} +# 這算是可讀性較好的 "if (!condition)" + +# 倒裝句型算是某「很 Perl 的」寫法 +print "Yow!" if $zippy; +print "We have no bananas" unless $bananas; + +# while +while (condition) { + ... +} + +my $max = 5; +# 以 for 迴圈,$i 為迭代變數 +for my $i (0 .. $max) { + print "index is $i"; +} + +for my $element (@elements) { + print $element; +} + +map {print} @elements; + +# 迭代變數為 $_ +for (@elements) { + print; +} + +# 對雜湊進行迭代(for 與 foreach 完全相同) + +foreach my $key (keys %hash) { + print $key, ': ', $hash{$key}, "\n"; +} + +# 又是「很 Perl 的」倒裝句法 +print for @elements; + +# 對一雜湊參照之中迭代,逐一走過其鍵與值 +print $hash_ref->{$_} for keys %$hash_ref; + +#### 正規表示式 + +# Perl 中,對正規表示式的支援既廣亦深,在 perlrequick、perlretut 等各處文件中 +# 都有更加完整的文件。不過,簡而言之: + +# 簡易比對 +if (/foo/) { ... } # 若 $_ 內含 "foo" 則為真 +if ($x =~ /foo/) { ... } # 若 $x 內含 "foo" 則為真 + +# 簡易取代 +$x =~ s/foo/bar/; # 將 $x 中第一個出現的 foo 換為 bar +$x =~ s/foo/bar/g; # 將 $x 中所有出現的 foo 換為 bar + +#### 檔案與輸出入 + +# 以 "open" 函式開檔後,便可自檔案輸入或對其輸出 + +# 讀檔: +open(my $in, "<", "input.txt") or die "Can't open input.txt: $!"; + +# 寫檔(若檔案已經存在,舊內容會被清空): +open(my $out, ">", "output.txt") or die "Can't open output.txt: $!"; + +# 寫檔(若檔案已經存在,會寫到檔尾去): +open(my $log, ">>", "my.log") or die "Can't open my.log: $!"; + +# 使用 "<>" 算符,能對檔案代號進行讀取。在純量語境下,會自檔案代號讀一列內容。 +# 而在串列語境下,對讀入整個檔案。每一列都會成為串列中一項元素。 + +my $line = <$in>; +my @lines = <$in>; + +# 以 "print" 函式,則可對檔案代號進行輸出。 + +print $out @lines; +print $log $msg, "\n"; + +#### 函式之撰寫 + +# 撰寫函式很是容易: + +sub logger { + my $logmessage = shift; + + open my $logfile, ">>", "my.log" or die "Could not open my.log: $!"; + + print $logfile $logmessage; +} + +# 之後,使用起來就與內建函式無異: + +logger("We have a logger subroutine!"); + +#### 模組 + +# 所謂模組,就是一組 Perl 程式碼,由一些函式組成,並可讓其他 Perl 程式碼來利用。 +# 為了讓 perl 能找至,通常模組之副檔名 .pm 。 + +package MyModule; +use strict; +use warnings; + +sub trim { + my $string = shift; + $string =~ s/^\s+//; + $string =~ s/\s+$//; + return $string; +} + +1; + +# 自他處利用: + +use MyModule; +MyModule::trim($string); + +# Exporter 模組能將函式出口,好讓它們能被這樣利用: + +use MyModule 'trim'; +trim($string); + +# 有許多 Perl 模組能從 CPAN (https://www.cpan.org) 下載下來,各式各樣的機能讓你 +# 能免於重新發明輪子。不少高人氣模組,如 Exporter,則是與 Perl 一同釋出、散佈。 +# 更多關於 Perl 模組的細節,詳見 perlmod 文件。 + +#### 物件 + +# Perl 中的物件,只是個參照,但同時又知道自己屬於哪個類別(package),於是對自身 +# 調用方法(函式)時方知去何處尋找函式本體。在建構子(通常是 "new")中,都是以 +# "bless" 函式來標記參照與其類別。只不過,若你使用像 Moose 或 Moo 模組的話,這些 +# 都不必自己來(總之請繼續往下讀)。 + +package MyCounter; +use strict; +use warnings; + +sub new { + my $class = shift; + my $self = {count => 0}; + return bless $self, $class; +} + +sub count { + my $self = shift; + return $self->{count}; +} + +sub increment { + my $self = shift; + $self->{count}++; +} + +1; + +# 以箭頭運算符,便可對某類別或某物件呼叫某方法: +use MyCounter; +my $counter = MyCounter->new; +print $counter->count, "\n"; # 0 +$counter->increment; +print $counter->count, "\n"; # 1 + +# CPAN 上的 Moose 與 Moo 模組能助你撰寫類別本體。它們提供了建構子,與簡單易懂的 +# 語法能來宣告屬性。前述的類別改寫之後,如下: + +package MyCounter; +use Moo; # 同時也啟用 strict 與 warnings + +has 'count' => (is => 'rwp', default => 0, init_arg => undef); + +sub increment { + my $self = shift; + $self->_set_count($self->count + 1); +} + +1; + +# 物件導向程式設計於 perlootut 文件中有詳盡的說明。 +# 此外,perlobj 文件中更涵蓋了底層實做之細節。 +``` + +#### 常見問答集 + +perlfaq 是問與答,涵蓋許多常見問題和解法,常常對該用哪些 CPAN 模組有很好的建議。 + +#### 延伸閱讀 + + - [perl-tutorial](http://perl-tutorial.org/) + - [Learn Perl](https://www.perl.org/learn.html) + - [perldoc](http://perldoc.perl.org/) + - 內建函式 : `perldoc perlintro` diff --git a/zh-tw/python-tw.html.markdown b/zh-tw/pythonlegacy-tw.html.markdown index cd7481d7..575897e2 100644 --- a/zh-tw/python-tw.html.markdown +++ b/zh-tw/pythonlegacy-tw.html.markdown @@ -1,5 +1,5 @@ --- -language: python +language: Python 2 (legacy) contributors: - ["Louie Dinh", "http://ldinh.ca"] - ["Amin Bandali", "http://aminbandali.com"] @@ -7,7 +7,7 @@ contributors: - ["evuez", "http://github.com/evuez"] translators: - ["Michael Yeh", "https://hinet60613.github.io/"] -filename: learnpython-tw.py +filename: learnpythonlegacy-tw.py lang: zh-tw --- @@ -16,7 +16,7 @@ Python是在1990年代早期由Guido Van Rossum創建的。它是現在最流行 非常歡迎各位給我們任何回饋! 你可以在[@louiedinh](http://twitter.com/louiedinh) 或 louiedinh [at] [google's email service]聯絡到我。 註: 本篇文章適用的版本為Python 2.7,但大部分的Python 2.X版本應該都適用。 Python 2.7將會在2020年停止維護,因此建議您可以從Python 3開始學Python。 -Python 3.X可以看這篇[Python 3 教學 (英文)](http://learnxinyminutes.com/docs/python3/). +Python 3.X可以看這篇[Python 3 教學 (英文)](http://learnxinyminutes.com/docs/python/). 讓程式碼同時支援Python 2.7和3.X是可以做到的,只要引入 [`__future__` imports](https://docs.python.org/2/library/__future__.html) 模組. |