前言
資料型態 (data type) 用來規範資料在電腦程式中所占的記憶體大小和合法的 (valid) 操作。例如,數字型態資料可以加減乘除,布林型態資料可進行邏輯運算等。本文介紹 Groovy 的資料型態。
萬物皆物件 (Everything is Object)
在 Java 中,型別分為基礎型態 (primitives) 和參考型態 (references) 兩種型態,差別在於後者可以使用物件導向語法,而前者不行。在 Groovy 中,沒有這樣的區分,所有的值皆為物件 (everything is object)。
在以下例子中,我們使用整數 3
的 times
方法 (method) 重覆執行三次程式:
3.times {
println "Hello World"
}
這個程式會印出三行 "Hello World"
字串;因為 3
是一個整數物件 (object),可以呼叫 times
方法。這是從 Ruby 吸收來的物件導向式語法,一開始可能會覺得不太習慣,寫一陣子 Groovy 後就會覺得這種寫法相當有用。
Groovy 對於物件的支援是透過一層 wrapper 將基礎型態包成參考型態,這個過程是自動轉換的,程式設計者不需手動處理這些 wrapper 類別。
內建資料型態
Groovy 沿用 Java 的資料型態,本節列出 Groovy 的內建資料型態。
基本型態 (Primitive Data Type)
以下是常用的基本型態 (base type):
- 布林 (
bool
) - 字元 (
char
) - 數字 (Number)
- 整數 (Integer)
Byte
Short
Integer
Long
BigInteger
- 浮點數 (Floating-point number)
Float
Double
BigDecimal
- 整數 (Integer)
- 字串 (String)
String
GString
所謂的基礎型態是指在這類型態的資料概念上是單一的 (atomic)。但在 Groovy 中,即使是基本型態,仍然可用物件導向語法撰寫程式,這是從 Ruby 吸收而來的特性。
參考型態 (Reference Data Type)
此外,常見的參考型態如下:
- 陣列 (array)
- 串列 (list)
- 映射 (map)
複合型別會有其搭配基礎型態,像是以字串為元素 (element) 的串列。
用類別建立資料型態
除了使用現有的類別,Groovy 可以用物件系統建立新的資料型態。Groovy 沿用 Java 的物件系統,並加上 Groovy 的改良。
布林 (Boolean)
布林型態用來表達數學上的布林運算,包括 true
和 false
兩種值,用來表示邏輯上的真與假。
不過,重要的是知道那些值會判定為 false
,這類值稱為 falsy value。如下:
false
- 數字為零
0
- 空字串
""
- 空物件
null
- 空陣列 (array)
- 空映射 (map)
- 空集合 (set)
除了 falsy value 外,其他的值本身會判定為真。
另外,可在類別中實作 asBoolean
方法 (method),有實作這個方法的物件可直接判定物件的真假。以下例子摘自 Groovy 官網:
class Color
{
String name
boolean asBoolean () {
name == 'green' ? true : false
}
}
數字 (Number)
雖然 Groovy 有許多種數字型態,但不太需要擔心要使用那一個型態,因 Groovy 會自動轉換。如以下實例:
def num = 2
assert num instanceof java.lang.Integer
num = num ** 100
assert num instanceof java.math.BigInteger
原先變數 num
是整數,但在運算後,超過整數的範圍,就自動轉為 Java 大數 (java.math.BigInteger 型別);這個特性在 Python 和 Ruby 等語言都有。
字串 (String)
Groovy 的字串,除了承接原有的 Java 字串的功能,也加上一些更方便的語法糖。例如,以下的 Java 程式將字串相接起來:
// Java code
public class MainProgram
{
public static void main(String[] args) {
String name = "Michelle";
// String concatenation
System.out.println("Hello " + name);
}
}
但是在 Groovy 中,可以用更簡潔的字串安插 (string interpolation) 語法,如下例:
def name = "Michelle"
println "Hello ${name}"
在 Groovy 中,字串分為以下數種
- 單引號字串
- 雙引號字串
- 三重單引號字串
- 三重雙引號字串
單引號字串和雙引號字串的差別,在於雙引號字串有字串安插的特性,而單引號則無。如下例:
def name = "Michelle"
assert 'Hello ${name}' == 'Hello ${name}'
assert "Hello ${name}" == 'Hello Michelle'
而三重引號字串則是用比較簡潔的方式表示多行字串,如下例:
def name = "Michelle Chen"
def job = "Programmer"
def msg = """\
Name: ${name}
Job: ${job}
"""
print msg
同樣地,雙引號字串有字串安插,單引號則無。
Groovy 對字串的外加功能,是因為 Groovy 另外實做了 GString 型別。在 Groovy 程式內部,會自動在 Java 字串 (java.lang.String 型別) 和 Groovy 字串 (groovy.lang.GString) 兩者之間自動轉換,使用者不需煩惱這些細節。如下例:
def name = "Michelle"
def greeting = "Hello ${name}"
assert name instanceof java.lang.String
assert greeting instanceof groovy.lang.GString
陣列 (Array) 和串列 (List)
在資料結構中,陣列 (array) 和連結串列 (linked list) 都是有序串列 (ordered list),但差別在於其內部實作。Groovy 的陣列和串列兩者從語法上看起來很像,實際上的差別在於其內部實作。
Groovy 中的有序串列有兩種:
- java.util.ArrayList,內部為動態陣列 (dynamic array),可變動大小
- java.util.LinkedList,內部為雙向連結串列 (doubly-linked list),可變動大小
這兩者都是有序串列,為什麼要區分為兩種實作呢?這主要是效率上的考量。陣列在隨機存取的效率好,但變動大小時效率較差;反之,串列在變動大小的效率好,隨機存取的效率則差。我們後文會再談陣列和串列的使用方式。
映射 (Map)
映射 (map) 是以鍵值對 (key-value pair) 為儲存單位的非線性資料結構。映射是相當實用的基礎資料結構,有些程式語言,像是 PHP 或 AWK,甚至只提供映射這類資料結構,再用映射去模擬陣列。我們後文會介紹映射。