3

重複の可能性:
Ruby では、初期化コンストラクターをオーバーロードする方法はありますか?

BigDecimal初期値のようにfloatを取らないので、それを扱うコンストラクタを書いています。初期化メソッドを無視して、デフォルトのコンストラクターを呼び出しているようです。

投げるTypeError can't convert Float into String (TypeError)

メソッドformatは機能します。

ファイル BigDecimal.rb:

require 'bigdecimal'

class BigDecimal

    def initialize
        if self.class == Float
            super self.to_s
        end
    end

    def format
        sprintf("%.2f", self)
    end

end

次に、ファイル test.rb で:

require 'BigDecimal' # => true
bd = BigDecimal.new('54.4477') # works
puts bd.format # 54.44
bd2 = BigDecimal.new(34.343) # TypeError: can't convert Float into String (TypeError)

ルビー1.9.2

4

2 に答える 2

7

コードの問題:

  1. 継承の代わりにモンキー パッチを使用するため、このメソッドでは、BigDecimal のスーパー クラスであるの initialize メソッドを呼び出しますinitialize。デフォルトのコンストラクターを呼び出すには、以下に示すように他の方法を使用する必要があります。superObject

  2. メソッドの引数を指定しませんでしたinitialize

  3. BigDecimal DOES は float をコンストラクタ引数として取ります

したがって、

  1. デフォルトのコンストラクターを直接使用して、float を次のように渡すことができます。

    BigDecimal.new(34.343, 5) # 5 is the precision
    
  2. この方法でコンストラクターをオーバーライドできます。

注: 通常はinitializeメソッドにエイリアスを設定します。ただし、この場合、これは機能しないようです (何らかの理由でinitialize呼び出されないため)。したがって、newより基本的なメソッドをエイリアスする必要があります。

    require 'bigdecimal'

    class BigDecimal

        class << self
          alias_method :__new__, :new  #alias the original constructor so we can call later
          def new(*args)
              if args.length == 1 && args[0].is_a?(Float)
                  __new__(args[0].to_s)
              else
                  __new__(*args)
              end
          end
        end

        def format
            sprintf("%.2f", self)
        end

    end

    BigDecimal.new(12.334)
    #<BigDecimal:10a9a48,'0.12334E2',18(18)>
于 2012-06-21T17:03:04.620 に答える
5

BigDecimalは、初期値のようにフロートを取りません

本気ですか?

BigDecimal.new(2.4)
#=>ArgumentError: can't omit precision for a Rational.

したがって、2番目の引数として精度を指定する必要があります。

BigDecimal.new(2.4, 2)
#=> #<BigDecimal:7ff689b0f2e8,'0.24E1',18(36)>

ドキュメントには、1.9.2と1.9.3の間の変更は示されていません。

于 2012-06-21T15:58:37.897 に答える