我想像许多其他语言一样在Ruby中使用重载功能,但Ruby本身不支持此功能.
我是否必须使用定义带*args参数的方法的方式来实现它,并确定方法内参数的数量和类型?有些人喜欢:
class A
def foo(*args)
case (args.length)
when 1
do something
when 2
do something-else
....
end
end
end
Run Code Online (Sandbox Code Playgroud)
你可以看到,它比直接重载更难看.
我想知道是否有任何关键字或其他方式(如元编程模块)可以让我以更优雅的方式定义重载方法.
你可以分别测试每个参数的存在,因为它们被设置为nil如果没有传递(假设它们按顺序传递!).
如果你坚持使用非常不同的参数,我建议用你想要的每个参数的符号哈希参数,并进行适当的测试.
**更新**
您还可以使用更具体的名称重命名重载的方法,例如
def perform_task_with_qualifier_1
Run Code Online (Sandbox Code Playgroud)
您可以尝试一些元编程来达到目标.
请参阅以下代码:
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
Run Code Online (Sandbox Code Playgroud)
您可以使用定义重载方法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
Run Code Online (Sandbox Code Playgroud)
def_overload为重载方法定义框架,overload_method定义一个'overload-method'.
你应该尝试适应Ruby的方式.有一个原因是Ruby中没有重载.方法应该只做一件事,而不是因为不同的论点而神奇地决定做出截然不同的事情.而是尝试利用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
Run Code Online (Sandbox Code Playgroud)
当你打电话给它
p x.ometh(1)
p x.ometh('a')
Run Code Online (Sandbox Code Playgroud)
你得到
"Called me with one parameter (1)"
"Called me with one string parameter (\"a\")"
Run Code Online (Sandbox Code Playgroud)