改文章源于Raddit上的一个问题:如何理解下面的代码?
def clone(opts = (return self; nil))
# ...
end
表达式与语句区别
Ruby中的表达式(expression)与语句(statement)。
表达式与语句的区别:二者都会被执行,但是表达式会返回值,语句不会返回值。
与Javascript不同的是,Ruby中的所有条件/循环结构都是表达式。
Ruby社区中,经常有句话:一切都是表达式。严格来讲,这句话并不完全正确。
空值表达式(Void value expression)
Ruby中包括6个语句(statement):return、retry、redo、next、break和alias。
虽然称作空值表达式,如果用上述语句代替表达式,Ruby解释器会抛SyntaxError,如:
x = return # 抛异常 SyntaxError: void value expression
只要不尝试访问语句(statement)的返回值,那么任何表达式可用的地方,都可以使用上述语句。
默认参数魔法
当尝试给方法参数提供默认值的时候,Ruby要求默认值是个表达式。每次需要默认值的时候,这个表达式都会被执行,将结果赋值给参数。
上面提到,只要不访问语句的返回值,那么语句可以放在任何表达式合法的地方,否则Ruby解释器抛出SyntaxError。为了绕开这异常,在return self后面加了nil(表达式)。当调用clone方法的时候,如果不传递参数,(return self; nil)会被执行。而return self的执行环境与方法体一致,因此,执行完return self后,clone方法立刻返回,将当前对象(self)作为返回值,nil表达式不可达,同时,clone的方法体也不会运行。
如果不这么实现,该怎么实现?
可以如下定义:
def clone(*opts)
// ...
end
但是,我们不得不判断数组opts的长度,当参数过长(在这个场景下,超过1个)时,抛ArgumentError错误。
同时,有人做了实现上的性能比较,该种方式(return self;nil)的性能是最佳的。
不过,从可读性上来讲,这种实现方式要慎用,很容易引起迷惑。