为什么ruby只允许默认参数和splats的某些排序?

时间:2013-06-09 02:03:05

标签: ruby

编码ruby时遇到了一个奇怪的情况:

def foo(bar=true,baz,*args)
end

引发此错误:

syntax error, unexpected tSTAR

而这些:

def foo(bar,baz=true,*args)
end

def foo(bar=true,baz=true,*args)
end

没关系。

为了增加陌生感,这些:

def foo(bar,baz=true)
end

def foo(bar=true,baz)
end

都工作。

但是,这个:

def foo(bar=true,baz,args=true)
end

引发错误,但是这些:

def foo(bar=true,baz=true,args)
end

def foo(bar,baz=true,args=true)
end

很好。

我认为有一个合乎逻辑的原因可以解释为什么允许某些组合而其他组合不允许,但我无法通过谷歌或搜索stackoverflow找到它们。我的问题很简单:为什么其中一些组合允许,而其他组合则不允许?

1 个答案:

答案 0 :(得分:5)

Ruby书籍在那里详细解释了这一点。但即使没有一个,你也会习惯它的逻辑。一个体面的编码器首先定义强制有序参数的函数,如下所示:

def foo( a, b, c=0, d=0 )
  # ...
end

简单地说,前2个args按顺序转到ab,最多2个cd的可选参数。但是你被赋予了超越普通体面的自由:

def foo( a=0, b )
  # ...
end

如果您提供1个参数,则转到b。如果您提供2个args,则会按顺序将其分配到ab。这不太合适,因为它需要用户更多的学习。如果你自己是用户,那么你就是在猥亵自己,但是,根本就没有语法模糊性。现在看看这个:

def foo( a=0, b, c=0 )
  # ...
end

如果您致电foo( 1, 2 ),您的意思是a = 1b = 2c = 0a = 0b = 1,{{1 }}?也许第一个更有可能,但编码规则是,不要猜测用户的意图。所以,Ruby团队可能决定不放纵这种语法。您仍然可以通过定义:

来实现它
c = 2

因此,实际上,您获得了绝对自由,但Ruby引导您进行良好实践:通过使良好的代码看起来比糟糕的代码更好。同样适用于使用* splat收集参数。体面的案例是明确的:

def foo( *args )
  a, b, c = case args.size
            when 1 then [0, args[0], 0]
            when 2 then [*args, 0]
            when 3 then args
            else fail ArgumentError; "#{args.size} arguments for 1..3!" end
  # ...
end

但是:

def foo( a, b=0, *c )
  # ...
end

当您致电def foo( a=0, b, *c ) # ... end 时,您的意思是foo( 1, 2, 3 )a = 1b = 2c = [3]a = 0和{ {1}}?因此,同样不鼓励这第二种情况,但仍然可以实现:

b = 1

使用许多参数编写函数,特别是使用许多有序参数,这是不好的做法。有句老话说,二元方法比三元方法好,一元优于二元方法,最后,比一元方法更好。如果你的方法需要很多参数,你应该通过replacing it with an object重构它。这是否回答了你的问题?