有没有办法覆盖对象上的&
方法,因此在调用时会返回一个数组:
class MyObject
end
o1, o2, o3 = MyObject.new, MyObject.new, MyObject.new
o1 # => #<MyObject0x01>
o1 & o2 # => [#<MyObject0x01>, #<MyObject0x02>]
o1 & o2 & o3 # => [#<MyObject0x01>, #<MyObject0x02>, #<MyObject0x03>]
答案 0 :(得分:7)
尝试制作自己的语法似乎很愚蠢。你为什么不只使用Ruby的数组符号?
[o1, o2, o3] # => [#<MyObject0x01>, #<MyObject0x02>, #<MyObject0x03>]
我是否忽视了一些明显的东西?
答案 1 :(得分:4)
简单的答案是否定的。冗长的答案是如果你返回一个数组,你将打破MyObject的引用链,然后开始调用Array 上的方法。基于The Principal of least surprise
的最佳解决方案使用[] << o1 << o2 << o3
或
[o1,o2,o3]
将<<
定义为数组
创建一个类
class MyObjectCollection < Array
def &
# do what I mean
end
end
Monky patch Array
引用链的解释
class MyObject
end
o1, o2, o3 = MyObject.new, MyObject.new, MyObject.new
o1 # => #<MyObject0x01> # <-- works
o1 & o2 # => [#<MyObject0x01>, #<MyObject0x02>] # <-- could work with def & because the LHS is a MyObject
o1 & o2 & o3 # => [#<MyObject0x01>, #<MyObject0x02>, #<MyObject0x03>] # <--- CANNOT work because o1 & o2 return an object of type Array and not of type MyObject
答案 2 :(得分:2)
阅读所有其他答案以获取重要细节。但这是一个解决方案:
class MyObject
def initialize(x)
@x = x
end
def &(arg)
return [self, arg]
end
def to_s
@x
end
end
class Array
def &(arg)
if arg.is_a? MyObject
return self << arg
else
# do what Array.& would normally do
end
end
end
a = MyObject.new('a')
b = MyObject.new('b')
c = MyObject.new('c')
x = a & b & c
puts x.class
puts "[#{x.join(', ')}]"
这是另一种更安全的解决方案(即没有monkeypatching):
class MyObject
def initialize(x)
@x = x
end
def &(arg)
a = MyObjectArray.new
a << self << arg
end
def to_s
@x
end
end
class MyObjectArray < Array
def &(arg)
return self << arg
end
end
a = MyObject.new('a')
b = MyObject.new('b')
c = MyObject.new('c')
x = a & b & c
puts x.class
puts "[#{x.join(', ')}]"
答案 3 :(得分:1)
我想,但是你还需要monkeypatch Array
,然后你就会发生冲突,因为Array
已经定义了&
。
为什么不定义<<
?然后在第一个运算符返回[o1, o2]
后,<<
已经拥有的Array
将为您提供DTRT。
>> class MyObject
>> def << x
>> raise ArgumentError unless x.is_a? self.class or is_a? x.class
>> [self, x]
>> end
>> end