为什么这个splat方法调用不能在Ruby中工作?

时间:2013-12-27 13:16:51

标签: ruby

def method(a, b='a', c, *d)
  [a,b,c, d]
end

p method(1,2,3,4)

不起作用,我不明白为什么,如果我们删除b参数一切正常。语法规则说你可以在splat参数之前使用默认值设置params。

3 个答案:

答案 0 :(得分:4)

具有默认值和splat变量的变量可以存在并且共存,只要具有默认值的变量可以被解释为(唯一的)splat的初始元素。

因此,这些都可以工作:

def good(a = :a, b);      [a,b];    end
def good(a = :a, *b);     [a,b];    end
def good(a, b = :b, *c);  [a,b,c];  end

但这些不会:

def bad(*a, b = :b);          [a,b];    end  # default after the splat
def bad(a = :a, b, c = :c);   [a,b,c];  end  # parsing would need two splats
def bad(a = :a, b, *c);       [a,b,c];  end  # parsing would need two splats
def bad(*a, b = :b, c);       [a,b,c];  end  # default after the splat

(Tbh,我不知道哪些实现细节会阻止Ruby在 splat之后立即接受默认值,前提是没有歧义。但我猜这是为了避免在splat上循环两次而不是一次,即性能,并且可能有其他原因可能与Ruby计算方法的方式有关。)

答案 1 :(得分:3)

默认参数(b)应位于位置参数(ac)之后:

def method(a, c, b='a', *d)
  [a,b,c, d]
end

答案 2 :(得分:0)

幕后发生了一些事情:

def method(a=7, b, *c); end
SyntaxError: (irb):25: syntax error, unexpected *
 def method(a=7, b, *c); end
                     ^
def method(*b, *c); end
SyntaxError: (irb):26: syntax error, unexpected *
 def method(*b, *c); end
                 ^  

请注意,这是同一个错误。当你将一个默认值的param放在固定参数列表末尾以外的任何地方时,我希望内部Ruby使用相同的结构来表示它用于splat的内容(Ruby C API方法是{{ 1}})。因此,由于对多个splats的相同限制,您不能拥有中间位置默认值。

AFAICS,这不是语言的技术限制,但实现细节 - 巧妙处理Ruby中非结束位置的默认值是重用splats使用的数据结构和逻辑。 splats 以这种方式受限制(因为两个splats是不明确的),但理论上可能有一个方案支持你的问题中的默认值。可能虽然这是一个不寻常的要求,你不会在不久的将来看到它完成。我建议只需将你的命名可选参数移到splat param之前。