位元詩人 [Perl] 程式設計教學:資料型態 (Data Type)

Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

說明

在電腦程式中,資料型態用來界定資料所占的記憶體大小及該資料合法的操作,像是數字間可進行四則運算,字串可相接等。

Perl 的內建資料型態如下:

  • 純量 (scalar)
    • 數字 (number)
    • 字串 (string)
    • 參考 (reference)
  • 陣列 (array)
  • 雜湊 (hash)

純量是單獨的值,陳列、雜湊則是容器。純量本身沒有綁定特定型態。寫 Perl 程式時也不需要宣告純量的型態,Perl 會自動判定純量當下的型態,並視需求自動轉換。

除了內建型態,Perl 有一套相對原始的物件系統。我們在先前的文章有說過,Perl 在當代的定位是有程式語言的命令列工具。對於學習 Perl 來說,物件系統不是很必要。

數字 (Number)

Perl 的數字可能是整數 (integer) 或浮點數 (floating-point numbers),支援以下表示法:

my $x = 12345;         # integer
my $x = 123.45;        # floating point
my $x = 6.02e23;       # scientific notation
my $x = 1000_000_000;  # long int with better readability
my $x = 0377;          # octal
my $x = 0xff;          # hexadecimal (hex)
my $x = 0b1100_0000;   # binary

前四個數字為一般常見的十進位數。但 Perl 支援其他進位系統:

  • 0 開頭表示八進位數
  • 0x 開頭表示十六進位數
  • 0b 開頭表示二進位數

要將字串轉為相對應的數字時,可用以下函式:

  • int:去除小數點部分,僅回傳整數
  • oct:轉成二進位、八進位、十六進位數
  • 浮點數可自動轉換

浮點數的誤差

由於浮點數內部儲存的方式,進行浮點數運算時有可能會引入微小的誤差。見下例:

my $n = 0;

while ($n != 1) {
    # Do something here.

    $n += 0.1;
}

在理想的狀態下,$n 每跑一輪迴圈會遞增 0.1,跑十輪後就可以終止此 while 迴圈。但是,每次進行小數運算時會引進微小的誤差,實際上 $n 會跳過 1 後繼續遞增,造成非預期的無窮迴圈。

解決浮點數誤差的想法如下:

|實際值 - 誤差值| < 誤差

要注意誤差無法消除,只能藉由運算儘可能地縮小誤差到合理的範圍內。

我們將前例改寫如下:

my $n = 0;

while (abs($n - 1) > 1 / 100000) {
    # Do something here.

    $n += 0.1;
}

隨著 $n 遞增,誤差會逐漸縮小,最後在滿足條件時迴圈會結束。這並不是 Perl 獨有的問題,而是大部分程式語言會碰到的議題。

只有 Raku 等少數語言可以進行精準的小數點運算,但實務上幾乎不會有程式人用 Raku 進行數值運算,不能過度依賴 Raku 等少數語言所提供的特性。

字串 (String)

字串實字可用一對 '' (單引號) 或是一對 "" (雙引號) 包起來,兩者的差別在於前者不會進行字串安插 (string interpolation) 而後者會。

以下是實例:

my $name = "ByteBard";

'Hello $name' == "Hello \$name" or die "Wrong value";
"Hello $name" == "Hello ByteBard" or die "Wrong value";

在使用單引號包住 Hello $name 時,$name 不會插入實際的值,而會保持字面上的字元;相對來說,使用雙引號包住同一字串時,$name 會代換成 "ByteBard",所以會得到不同的結果。

\ (slash) 在雙引號字串的意思是跳脫下一個字元原本的意思,像是 \$ 代表不要解析 $ 而把其視為普通字串。有些字母會有特殊意義,如下:

  • \n:換行
  • \t:插入 TAB
  • \\:將下一個 \ 視為普通字串
  • \$:將下一個 $ 視為普通字串

這裡有更多的跳脫字元,讀者可自行參考。

特殊字串括號

除了原本的單/雙引號之外,Perl 還支援另一套寫法:

  • q//:相當於單引號字串
  • qq//:相當於雙引號字串
  • qx//:將字串視為命令列程式來執行
  • qw//:字串串列
  • qr//:正規表示式

為什麼要引入這套寫法呢?這是為了避免過多的 \ (slash),如下例:

my $name = "ByteBard";

qq("Perl is awesome!", $name said.) eq "\"Perl is awesome!\", $name said." 
    or die "Wrong value";

使用正規的雙引號字串時,我們要跳脫內部的雙引號,以免字串提早結果,但用 qq() 代替雙引號時,則不需跳脫內部的雙引號,可簡化程式碼。

自動型態轉換

Perl 會根據程式所在的情境境自動將資料轉換型態。如下例:

"2" * 3 == 6 or die "Wrong value\n";

Perl 程式會自動將字串 "2" 轉為數字 2 後進行運算。這樣的程式碼不是好的寫法,只是用來展示 Perl 的特性。

參考 (Reference)

參考是相對進階的概念,主要用於製作複合資料結構 (complex data structures),像是多維陣列或是混合陣列及雜湊的結構等。初階的 Perl 程式不會用到參考。

陣列 (Array)

陣列是線性 (linear)、有序的 (ordered) 容器。我們會在後文介紹陣列。

雜湊 (Hash)

雜湊是以鍵值對 (key-value pair) 為儲存單位的非線性 (non-linear) 容器。我們會在後文介紹雜湊。

關於作者

身為資訊領域碩士,位元詩人 (ByteBard) 認為開發應用程式的目的是為社會帶來價值。如果在這個過程中該軟體能成為永續經營的項目,那就是開發者和使用者雙贏的局面。

位元詩人喜歡用開源技術來解決各式各樣的問題,但必要時對專有技術也不排斥。閒暇之餘,位元詩人將所學寫成文章,放在這個網站上和大家分享。