Ruby Splat(*)符號使用

*符號英文稱為Asterisk或Splat,中文尚未看到統一稱呼,一般是稱為乘號或星號。一般常見於乘法,但在乘法用途中,是當做雙元運算子。當用作單元運算子的時候,他會有非常豐富多元的用途。

多個變數轉換為數列

*用於單元運算子,第一種用法是將一串變數轉換為數列:

*a = 1,2,3
# a = [1,2,3] 

反過來,也可以將數列轉換為一串變數,並帶入method中使用:

def sum(*args)
    puts args.inject(:+)
end

sum(1,2,3)
# => 6

也可以先指定第一個變數為主要用途,再帶入剩餘的變數:

def say(person, *words)
    words.each { |w| puts person + ": " + w }
end

say("John", "Hello", "My name is john", "I am 30 years old")
# => John: Hello
# => John: My name is john
# => John: I am 30 years old

利用*符號,可以讓一個method帶入多個變數而不會出現Wrong number of argument的錯誤。

同樣的方法可以交換順序使用,把數列放在最前面,而最後面是固定使用的變數:

def say(*words, person)
    words.each { |w| puts person + ": " + w }
end

say("Hello", "My name is john", "I am 30 years old", "John")
# => John: Hello
# => John: My name is john
# => John: I am 30 years old

看得出來嗎?整個功能與上個例子的相同,只有帶入的順序不同。另外,splat符號也可以將數列切成一串的變數帶入method中,以上方的say method為例:

sentences = ["Hello", "Nice to meet you", "How are you?"]

say("Nancy", *sentences)
# => Nancy: Hello
# => Nancy: Nice to meet you
# => Nancy: How are you?

這樣一來,就可以利用splat將數列整個帶入method當中,不需再多做處理。

多重指定變數Parallel Assignment

大家應該都知道Ruby當中可以在同一行指定變數:

a,b = "hello ", "world" 

puts a + b
# => hello world

而使用splat符號,可以大幅增加指定變數的空間:

first, *all = [1,2,3,4,5]
# first = 1
# all = [2,3,4,5]

*all, last = [1,2,3,4,5]
# all = 1,2,3,4
# last = 5

first, *all, last = [1,2,3,4,5]
# first = 1
# all = [2,3,4]
# last = 5

其他用法

還有一個奇妙用法,就是用來避開method的錯誤訊息。設定如果帶入太多參數,其他不用的就捨棄:

def plus(a, b, *)
    puts a + b
end

plus(1, 2, 3, 4, 5)
# => 3

上述例子中,只有1和2有實際帶入method中計算,不過這種防呆機制不易察覺有bug,無法及時補救,不建議使用。

參考資料

The Strange Ruby Splat

Splatt用法範例