(转载)Ruby中的星号操作符(Splat Operator)
本文转载自 lazybios 在 10条的文章 Ruby: Ruby中的星号操作符(Splat Operator) 2015-09-08 18:11 lazybios
严格的讲,应该不叫做星号操作符(,*),至少我在国外的文章中看到的都是叫做Splat Operator,我们姑且通过字形来这样称呼它吧。有知道怎么翻译的同学,麻烦给我说一下。Ok,下面一起看看它的出现场景
方法定义
def say(what, *people)
people.each{|person| puts "#{person}: #{what}"}
end
say "Hello!", "Alice", "Bob", "Carl"
# Alice: Hello!
# Bob: Hello!
# Carl: Hello!
上面星号操作符(Splat Operator)出现在方法定义的参数中,用来收集参数匹配后剩余额外的参数,可以算是一个语法糖。代码中,what
会获取方法调用中的第一个参数,*people
用来捕获除第一个参数之外的所有参数。
这里需要说明的是方法定义中没有明确的要求Splat Operator操作符出现的位置,没有必要一定要固定到参数的末尾。如下代码:
def arguments_and_opts(*args, opts)
puts "arguments: #{args} options: #{opts}"
end
arguments_and_opts 1,2,3, :a=>5
# arguments: [1, 2, 3] options: {:a=>5}
虽然没有位置的限定,但是却有规定不允许在定义方法时同时出现两个及以上的Splat Operator。否则会报语法错误
方法调用
除了能在方法定义中使用Splat Operator之外,还可以在方法调用中使用,继续结合上面的代码
people = ["Rudy", "Sarah", "Thomas"]
say "Howdy!", *people
# Rudy: Howdy!
# Sarah: Howdy!
# Thomas: Howdy!
def add(a, b)
a + b
end
pair = [3, 7]
add *pair #=> 7
上面两段代码,第一段中因为方法say定义的时候用到了Splat Operator,所以不会对people中的参数个数进行限制,第二段add方法定义时明确限定了参数个数,所以通过add *pair
调用的时候,必须对参数个数进行限制,否则会报ArgumentError
异常。
所以方法调用中的Splat Operator其实算是一种传递数组参数的语法糖。其形式等价与将参数一个一个传入。
多变量赋值
Ruby内置支持多变量赋值,如下面代码:
x, y = 10, 20
x, y = y, x
puts "#{x}, #{y}"
# 20, 10
但有时,我们还需要下面这样的赋值场景
letters = ["a", "b", "c", "d", "e"]
first, *second = letters
puts "#{first}, #{second}"
#=> a, ["b", "c", "d", "e"]
上面代码,将首个参数赋值给了first,剩余的参数直接通过数组打包赋值给了second。比如下面这段快排代码,就很好的利用了Splat Operator这一特性去选择中轴值,简化了语法描述。
def qsort(list)
return [] if list.size == 0
x, *xs = *list
less, more = xs.partition{|y| y < x}
qsort(less) + [x] + qsort(more)
end
数组相关
上面关于Splat Operator的三个使用场景,基本都涉及到了数组,与数组相关的还有下面两个特性
- 拼接数组
some_numbers = [1, 2, 3]
up_to_five = [*some_numbers, 4, 5]
p up_to_five
# [1, 2, 3, 4, 5]
- 强制类型转换
a = *"Hello" #=> ["Hello"]
"Hello".to_a #=> NoMethodError: undefined method `to_a' for "Hello":String
a = *(1..3) #=> [1, 2, 3]
a = *[1,2,3] #=> [1, 2, 3]
通过Splat Operator可以确保一个值为数组类型,特别是对与那些不支持to_a
的方法一样适用。
**含义
除前面的Splat Operator(*)外,Ruby2.0也引入了Double Splat Operator(**),与Splat Operator不同的是,Double Splat Operator返回值为Hash键值对,而不数组形态,可以视其为Hash类型的语法糖。
示例代码
def foo(a, *b, **c)
[a, b, c]
end
> foo 10
=> [10, [], {}]
> foo 10, 20, 30
=> [10, [20, 30], {}]
> foo 10, 20, 30, d: 40, e: 50
=> [10, [20, 30], {:d=>40, :e=>50}]
> foo 10, d: 40, e: 50
=> [10, [], {:d=>40, :e=>50}]
这个样子的参数传递,感觉跟Python函数定义中的参数赋值规则又差不多了。类比的运用记忆吧。
-完-
参考引用 http://t.cn/Rw7dqjZ