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

为什么这个splat方法调用在Ruby中不起作用?,ruby,Ruby,不起作用,我不明白为什么,如果我们去掉b参数,一切都会很好。语法规则规定,您可以将带有默认值的参数放在splat参数之前。默认参数(b)应该放在位置参数(a,c)之后: 引擎盖下面发生了一些事情: def method(a, c, b='a', *d) [a,b,c, d] end 请注意,这是相同的错误。当您将一个带有默认值的参数放置在固定参数列表末尾以外的任何位置时,我希望Ruby内部使用与splat相同的结构来表示该参数(Ruby C API方法是rb\u scan\u args)。

不起作用,我不明白为什么,如果我们去掉b参数,一切都会很好。语法规则规定,您可以将带有默认值的参数放在splat参数之前。

默认参数(
b
)应该放在位置参数(
a
c
)之后:


引擎盖下面发生了一些事情:

def method(a, c, b='a', *d)
  [a,b,c, d]
end
请注意,这是相同的错误。当您将一个带有默认值的参数放置在固定参数列表末尾以外的任何位置时,我希望Ruby内部使用与splat相同的结构来表示该参数(Ruby C API方法是
rb\u scan\u args
)。因此,由于对多个SPlat施加了相同的限制,因此不能具有中间位置默认值


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

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

因此,这些都将起作用:

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
                 ^  
但这些不会:

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

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

那么这段代码为什么工作:def method(a='a',b)[a,b]end p method(1,2)@daremarkovic,这在Ruby 1.8中是不允许的。在Ruby 1.9.2(?)+中,它相当于
def method(b,a='a')[a,b]end
。您可以通过调用
p method(1)来确认这一点
。我明白了,不确定等价性,虽然这完全有道理,但你有没有一些链接可以阅读更多关于它的内容,找不到任何地方有人这样说。@daremarkovic,看看你的ruby版本是什么?我使用ruby 2.0版本。相关:不相关,这里的splat在默认值之后……问题是默认值在
c ,在splat之前。为了更清楚地表明您的观点,您不需要方法定义体,也不需要调用方法。@sawa:我不理解“是语法的”?支持
方法(a=7,b,*c)
方法(a,b=7,*c)在逻辑上是一致的
,可以对fixed、optional和splat运算符进行相同的参数扩展和分配。但是,Ruby只支持第二种语法。换句话说,“valid”.但是我忽略了你的条件作用
,除了固定参数列表的末尾,所以我删除了前面的注释。Denis,你的附加注释,当默认值出现在splat之后时,会不会有歧义?我很确定,在理论上,它会工作得很好,使用不同的实现。我想,问题在于这一点y的内部处理变量默认值的方式与处理splat开头的方式相同。这意味着,如果它运行到
*a,b=:b
,它会在内部调用一些C函数,这基本上相当于
扫描splat\u args()
遇到
*a
;再次遇到
b=:b
。这在术语上会引发一个错误,因为您不能有两个splat。我怀疑,底层的rational相当于性能原因,因为这样做会避免look-aheads。Denis,您能给出一个调用
方法(*a,b=:b)的示例吗
是明确的吗?我认为原因很简单。
方法(1)
方法(1,2)
方法(1,2,3)
方法(a=:a,*b,c=:c)
如果我们在splat之前填充所有默认值,并且从左到右填充,那么它将是明确的。但是解析起来会更困难、更慢。(不过,如果Ruby支持的话,我不会感到更惊讶。)我终于明白你的意思了,但我可以看出这种行为会导致混乱和弹性错误。无论如何,几分钟后,我会将我的评论作为非建设性的混乱删除。
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