Ruby Ampersand方法

时间:2011-01-02 07:13:52

标签: ruby

有没有办法覆盖对象上的&方法,因此在调用时会返回一个数组:

class MyObject
end

o1, o2, o3 = MyObject.new, MyObject.new, MyObject.new

o1 # => #<MyObject0x01>
o1 & o2 # => [#<MyObject0x01>, #<MyObject0x02>]
o1 & o2 & o3 # => [#<MyObject0x01>, #<MyObject0x02>, #<MyObject0x03>]

4 个答案:

答案 0 :(得分:7)

尝试制作自己的语法似乎很愚蠢。你为什么不只使用Ruby的数组符号?

[o1, o2, o3] # => [#<MyObject0x01>, #<MyObject0x02>, #<MyObject0x03>]

我是否忽视了一些明显的东西?

答案 1 :(得分:4)

简单的答案是否定的。冗长的答案是如果你返回一个数组,你将打破MyObject的引用链,然后开始调用Array 上的方法。基于The Principal of least surprise

的最佳解决方案
  1. 使用[] << o1 << o2 << o3[o1,o2,o3]

  2. <<定义为数组

  3. 创建一个类

        class MyObjectCollection < Array
            def &
                # do what I mean
            end
        end
    
  4. Monky patch Array


  5. 引用链的解释

    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