我正在编写一个gem,希望在C扩展中实现条件赋值。
该想法是为logical defined-or提供分配。仅当变量为nil
时才分配。例如...
var = false
var //= 42 # var is false
var = nil
var //= 23 # var is 23
我在ruby/ruby
存储库中发现了abbreviated assignment的定义:
There are also ||= and &&=. The former makes an assignment if
the value was nil or false while the latter makes an assignment
if the value was not nil or false.
我没有在源代码中找到参考。 (如下面的||=
注释中所述,它不是运算符,而只是语法糖)
我试图在apidock.com上查看一些爆炸方法的定义:例如Array#map!
:
static VALUE
rb_ary_collect_bang(VALUE ary)
{
long i;
RETURN_ENUMERATOR(ary, 0, 0);
rb_ary_modify(ary);
for (i = 0; i < RARRAY_LEN(ary); i++) {
rb_ary_store(ary, i, rb_yield(RARRAY_PTR(ary)[i]));
}
return ary;
}
我设法遵循array.c
中对rb_ary_modify
和rb_ary_store
的引用。
您知道如何实现一种变异方法,例如:
require 'logic_or'
# Current behaviour
nil.lor('a') # => "a"
false.lor('a') # => false
a = nil # => nil
a.lor('a') # => "a"
a # => nil
# Expected behaviour
a = nil # => nil
a.lor!('a') # => "a"
a # => "a"
更新
正如评论中所指出的那样,先前的标题(如何用ruby实现Double pipe或等值(|| =)?)与问题的内容不一致
答案 0 :(得分:2)
我认为您无法实现val //= 23
,Perl将其称为“ dor”(定义或)。没有底层方法调用。相反,val ||= 23
被编译为...
if !val
val = 23
end
val //= 23
是...
if val.nil?
val = 23
end
您可以find the code for this in compile.c。您必须以某种方式修改解析器以添加新的idDOROP
操作码并更改语法。这不是不可能,它一直在Perl中完成,但是非常混乱。
我也不认为您可以做val.dor(23)
。那将需要分配到self
,这是不允许的。
class Object
def dor(value)
self = value if self.nil?
end
end
Can't change the value of self
self = value if self.nil?
我能想到的最接近的是这个。
class Object
def dor(value)
value if self.nil?
end
end
obj = obj.dor(42)
puts obj
相对于...而言,这是值得怀疑的改进
obj = 42 if obj.nil?
puts obj
通常,在Ruby中//=
不是必需的。 //=
之所以出现在Perl中,是因为Perl认为0
和""
是错误的。在许多情况下,这些值是有效值,但会被$var ||= $default
抹去。人们对写$var = $default if !defined $var
感到厌倦,//=
诞生了。
在Ruby中,只有两个错误值nil
和false
。其他一切都是真的。 var ||= default
将对0
和""
做正确的事情,因此几乎不需要//=
。
如果您的设计需要经常区分nil
和false
来编写新的运算符,请更改设计。