Ruby 如何以正确的姿势传一个 hash 参数

dongqs · 2014年07月22日 · 最后由 ruohanc 回复于 2014年07月31日 · 6611 次阅读

某个 method 需要传很多不确定的参数,以下两种姿势有什么区别么?大家一般会怎么写?

def foo **options puts options.inspect end

def bar options puts options.inspect end

foo msg: 'hello' bar msg: 'world'

这样的设计本身就是一种 bad design. 支持的参数一定要明确定义。一些 optional 的参数可以加默认值。何谈正确的姿势。

#1 楼 @xds2000 我在描述中省略了明确定义的那些参数,实际项目中是存在的 def foo id, msg, options puts id puts msg run_another_method options end

另,这些 optional 的参数是用来传递给更底层的 method 的,foo 本身并不关心里面放了些啥

歪楼了。楼主就想知道 *options 和 options 的区别。 这里一个的意思看这里: https://stackoverflow.com/questions/918449/what-does-the-unary-operator-do-in-this-ruby-code/918475#918475

*options 在参数里就是用 options 代替一个参数 Array,在前面再有一个就是展开这个 Array

抬头,做直,双手放在键盘上,眼睛看着屏幕。好了,现在你可以用这个正确的姿势来传递 hash 参数了。

#3 楼 @xds2000 一个的情况还是很明确的。我看到 rails 源代码里有很多 def foo arg1, arg2, options = {},似乎options 没有存在的必要,但 ruby 语法又提供了这样的功能,而且似乎两者还是有一些区别的,比如*options 无法设置默认值。于是好奇一下有没有人用过这样的写法

#5 楼 @dongqs https://ruby-china.org/topics/9447

options = {} 就等同于 **options

这个其实关乎方法参数位置的问题.

def a_method a, b="yo", *msgs, c,  key_param: "value",  **options, &block
  puts "a=#{a}"
  puts "b=#{b}"
  puts "msgs=#{msgs}"
  puts "c=#{c}"
  puts "key_param: #{key_param}"
  puts "options: #{options}"
  puts "block: #{block.call}"
end

a_method "called", "with", "lots", "of", "params", and: "a custom key param" do
  "and a block"
end

产出

a=called
b=with
msgs=["lots", "of"]
c=params
key_param: value
options: {:and=>"a custom key param"}
block: and a block

还有另外一个问题是 **options 是 2.0 才引入的新语法..对之前的不兼容...

#5 楼 @dongqs 有用的

# ruby不允许这样的语法( options默认值如果不是hash话无法传值,并且编译器分析不出来
def a b: 1, options = {}
end

# 所以这种情况只能用
def a b: 1, **options
end

#9 楼 @ruohanc 怪不得,我在书里面没看到过,只在 python 里面见过。

#2 楼 @dongqs 调用方法方不关心哪些参数是这个方法处理,哪些参数是方法里面调用其他方法处理。

#8 楼 @ruohanc #10 楼 @jjym #12 楼 @Rei 谢谢各位提供的信息,另外似乎不加 ** 传递的是引用,加上就变成传值了,是这样吧?

def foo **options
  options[:foo] = true
end
options = {msg: 'hello'}
foo options
puts options.inspect
=> {:msg=>"hello"}

def bar options
  options[:bar] = true
end
options = {msg: 'hello'}
bar options
puts options.inspect
=> {:msg=>"hello", :bar=>true}

#13 楼 @dongqs 不是,你打印下 object_id 看。(ruby 不分值和引用,都是引用

#14 楼 @jjym 试了一下,确实都是一样的 object_id,那如何解释两者的不同呢?

object_id 不一样

语法的区别我在 #10 说了

2.1.2 :001 > def foo **options
2.1.2 :002?>   options[:foo] = true
2.1.2 :003?>   p options.object_id
2.1.2 :004?>   end
 => :foo
2.1.2 :005 > options = {msg: 'hello'}
 => {:msg=>"hello"}
2.1.2 :006 > p options.object_id
14588640
 => 14588640
2.1.2 :007 > foo options
14573680
 => 14573680
2.1.2 :008 > p options
{:msg=>"hello"}
 => {:msg=>"hello"}

#16 楼 @jjym 嗯。。。是我搞错了,object_id 是不一样的

#8 楼 @ruohanc 如何让 b 取默认值'yo'?能给一个调用吗?

#18 楼 @5swords 是没办法的.

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册