11

Ruby のオーバーロード機能を他の多くの言語と同じように使いたいのですが、Ruby 自体はこの機能をサポートしていません。

*args引数でメソッドを定義し、メソッド内の引数の数と型を決定する方法を使用して実装する必要がありますか? いくつかのような:

class A
    def foo(*args)
        case (args.length)
        when 1
            do something
        when 2
            do something-else
        ....
        end
    end
end

ご覧のとおり、直接オーバーロードするよりも本当に醜いです。

より洗練された方法でオーバーロード メソッドを定義できるキーワードまたはその他の方法 (メタプログラミング モジュールなど) があるかどうかを知りたいです。

4

4 に答える 4

5

ターゲットに到達するために、メタ プログラミングを試すことができます。

次のコードを参照してください。

class OverloadError < ArgumentError; end
class Class
=begin rdoc

=end
  def define_overload_method( methodname, *methods )    
    methods.each{ | proc |
      define_method("#{methodname}_#{proc.arity}".to_sym, &proc )
    }
    define_method(methodname){|*x|
      if respond_to?("#{methodname}_#{x.size}")
      send "#{methodname}_#{x.size}", *x
      else
        raise OverloadError, "#{methodname} not defined for #{x.size} parameters"
      end
    }

  end
end

class X
  define_overload_method :ometh,
        Proc.new{ "Called me with no parameter" },
        Proc.new{ |p1| "Called me with one parameter (#{p1.inspect})" },
        Proc.new{ |p1,p2| "Called me with two parameter (#{p1.inspect}, #{p2.inspect})" }
end

x = X.new

p '----------'
p x.ometh()
p x.ometh(1)
p x.ometh(1,2)
p x.ometh(1,2,3)  #OverloadError

でオーバーロードされたメソッドを定義できますdefine_overload_method。パラメータは、メソッド名とプロシージャのリストです。メソッドmethodnameが作成され、対応するメソッドが呼び出されます。どのメソッドがパラメータの数によって決定されるか (タイプではありません!)。

別の構文は次のとおりです。

class OverloadError < ArgumentError; end
class Class
  def def_overload( methodname)    
    define_method(methodname){|*x|
      if respond_to?("#{methodname}_#{x.size}")
      send "#{methodname}_#{x.size}", *x
      else
        raise OverloadError, "#{methodname} not defined for #{x.size} parameters"
      end
    }
  end
  def overload_method( methodname, proc )    
    define_method("#{methodname}_#{proc.arity}".to_sym, &proc )
  end
end
class X
  def_overload :ometh
  overload_method :ometh, Proc.new{ "Called me with no parameter" }
  overload_method :ometh, Proc.new{ |p1| "Called me with one parameter (#{p1.inspect})" }
  overload_method :ometh, Proc.new{ |p1,p2| "Called me with two parameter (#{p1.inspect}, #{p2.inspect})" }
end

def_overloadオーバーロードされたメソッドのフレームを定義し、overload_method1 つの「オーバーロード メソッド」を定義します。

しかし、ホルガーがすでに述べたように:

Ruby のやり方に適応するように努めるべきです。Ruby にオーバーロードがないのには理由があります。メソッドは 1 つのことだけを行うべきであり、引数が異なるという理由だけで魔法のように非常に異なることを行うように決定する必要はありません。代わりに、Duck Typing を利用してみてください。疑わしい場合は、意味のある名前の別のメソッドを使用してください。


型依存のオーバーロードを使用してバージョンを実装する方法に興味がありました。ここにあります:

class OverloadError < ArgumentError; end
class Class
  def def_overload( methodname)    
    define_method(methodname){|*x|
      methname = "xxx"
      methname = "#{methodname}_#{x.size}#{x.map{|p| p.class.to_s}.join('_')}"
      if respond_to?(methname)
        send methname, *x
      elsif respond_to?("#{methodname}_#{x.size}")
        send "#{methodname}_#{x.size}", *x
      else
        raise OverloadError, "#{methodname} not defined for #{x.size} parameters"
      end
    }
  end
  def overload_method( methodname, *args, &proc )    
    types = []
    args.each{|arg| types << arg.to_s}
    define_method("#{methodname}_#{proc.arity}#{types.join('_')}".to_sym, &proc )
  end
end
class X
  def_overload :ometh
  overload_method(:ometh){ "Called me with no parameter" }
  overload_method(:ometh, String ){ |p1| "Called me with one string parameter (#{p1.inspect})" }
  overload_method(:ometh ){ |p1| "Called me with one parameter (#{p1.inspect})" }
  overload_method(:ometh){ |p1,p2| "Called me with two parameter (#{p1.inspect}, #{p2.inspect})" }
end

で呼び出すと

p x.ometh(1)
p x.ometh('a')

あなたが得る

    "Called me with one parameter (1)"
    "Called me with one string parameter (\"a\")"
于 2012-04-14T21:48:39.373 に答える
5

渡されない場合は nil に設定されるため、各引数の存在を個別にテストできます (順番に渡されると仮定します!)。

非常に異なる引数を主張する場合は、意図する各引数のシンボルを含むハッシュ引数を提案し、適切なテストを行います。

** アップデート **

また、次のようなより具体的な名前でオーバーロードするメソッドの名前を変更することもできます。

def perform_task_with_qualifier_1
于 2012-04-14T20:06:29.450 に答える
-1

オーバーロードの明確な特徴は、ディスパッチが静的に発生することです。Rubyでは、ディスパッチは常に動的に発生します。他に方法はありません。したがって、Rubyではオーバーロードはできません。

于 2012-04-14T23:22:26.050 に答える