Ruby对自定义类的隐式强制

时间:2014-03-22 14:00:08

标签: ruby class coercion

我有自己的班级

class Mutnum
    attr_reader :value
    def initialize(number)
        raise TypeError, "Mutnum created on a non-numeric value" unless number.is_a? Numeric
        @value = number
    end
    def ==(other)
        if other.is_a? Mutnum
            other.value == @value
        else
            @value == other
        end
    end
    def set(newval)
        @value = newval
    end
    def to_i
        @value
    end
    def to_s
        @value.to_s
    end
    def +(other)
        if other.is_a? Numeric
            @value + other
        elsif other.is_a? Mutnum
            Mutnum.new(@value + other.value)
        end
    end
    def coerce(other)
        if other.is_a? Numeric
            [other, @value]
        else
            super
        end
    end
end

其功能基本上是一个可变数字(例如,我可以将一个传递给一个函数,在该函数中更改它,并从它被调用的位置读取结果)。我正在使用它来使wxRuby和gosu在相同的应用程序中使用更少刺激。

我希望能够Array#[Mutnum][1,2,3,4][Mutnum.new(3)]4会导致[1,2,3,4][Mutnum.new(3).to_i]

我应该向Mutnum 编辑添加哪些其他功能,以便我可以将Mutnums用作数组索引 \ edit ?我想我可以说{{1}},但我必须做更多的调试。

1 个答案:

答案 0 :(得分:0)

没有可变数字这样的东西。但是有些数据结构可以包含一个数字。 MutableNumber通常不是他们的好名字。使用此类容器类的方法是:

class Container
  attr_accessor :value

  def initialize value
    @value = value
  end
end

A, B = Container.new( 42 ), Container.new( 43 )

对于你想做的事,你将不得不说

[1, 2, 3, 4][ Container.new( 3 ).value ]

克服它。 可以将许多方法委托给@value,假设它是Numeric子类之一。但是使用Array#[]方法,它不会起作用,因为它的原理是不同的。要点是,容器实际上是不是数字。

您必须定义

class EasyArray < Array
  def [] arg
    index = arg.value rescue arg
    super index
  end
end

EasyArray[ 1, 2, 3, 4 ][ Container.new( 3 ) ] #=> 4

总而言之,你最好的选择是不要定义自己的conntainer类,而是使用我的YNelson gem中的Petri网; gem install y_nelson。安装后,使用Petri网场所作为容器:

require 'y_nelson' and include YNelson
P, Q = Place( m: 2 ), Place( m: 3 )
[ P, Q ].map &:value #=> 2, 3

请记住,当计算机科学家想要可变数字时,他们会使用Petri网。