3

我在编写 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。我的问题很简单:为什么其中一些组合是允许的,而另一些则不允许?

4

1 回答 1

5

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

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

简单地说,前 2 个 args 转到a, b,然后最多 2 个可选 args 到c, d, 。但是你被授予了超越一般体面的自由:

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

如果您提供 1 个参数,它将转到b. 如果您提供 2 个参数,它们将按顺序分配给a, b, 。这不太体面,因为它需要从用户那里学习更多。如果您自己是用户,那么您就是对自己不雅,但仍然没有语法歧义。现在看看这个:

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

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

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

因此,事实上,你被赋予了绝对的自由,但是 Ruby 会引导你进行良好的实践:让好代码看起来比坏代码更好看。同样适用于使用 * splat 收集参数。体面的案例是明确的:

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

但是有:

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

当你打电话时foo( 1, 2, 3 ),你的意思是a = 1, b = 2, and c = [3], or a = 0, b = 1, andc = [2, 3]吗?因此,同样,不鼓励第二种情况,但仍然可以实现:

def foo( *c )
  a, b = case c.size
         when 0 then fail ArgumentError, "Too few arguments!"
         when 1 then [0, c.shift]
         else [c.shift, c.shift] end
  # ...
end

编写具有许多参数的函数,尤其是具有许多有序参数的函数是不好的做法。有句老话,二元比三元好,一元比二元好,最后,零比一元好。如果你的方法需要很多参数,你应该用一个 object 替换它来重构它。这回答了你的问题了吗?

于 2013-06-09T02:21:25.653 回答