例如,如果我有
def function(arg)
#do stuff
end
我如何才允许arg
成为数组?我能做到
def function(arg)
if arg.class != 'Array'
return 'Error'
else
#do stuff
end
end
但有没有更好的方法呢?
答案 0 :(得分:8)
你不能像其他语言那样def function(Array arg)
,但你可以用一个代替你的第二个片段的四行:
def function(arg)
raise TypeError unless arg.is_a? Array
# code...
end
答案 1 :(得分:4)
其他人已经指出你如何在技术上强制执行一种论证,但你正在与红宝石的思维方式进行根本性的斗争。谷歌围绕着#duck; duck typing"。
在红宝石世界中,我们通常不会担心参数的类型,而是它是否符合我们想要用它做什么的界面。换句话说,它像鸭子一样嘎嘎叫吗?够好了!
让我们假设您正在尝试使用数组:
def function(arg)
arg.each do |a|
puts a
end
end
如果您将其称为:function(1)
,则会获得NoMethodError: undefined method 'each'
让我们使用你强迫它成为数组的想法。
def function(arg)
raise TypeError unless arg.is_a? Array
arg.each do |a|
puts a
end
end
好的,现在我们犯了一个不同的错误,但是如果使用除数组之外的其他方法调用该方法,则仍然会生成错误。
此外,这个怎么样?
function("Hello World".chars)
糟糕,我们有一个错误,尽管函数会起作用!
红宝石的方式更像是:
def function(arg)
if arg.respond_to? :each
arg.each do |a|
puts a
end
else
puts arg
end
end
现在,您的功能适用于各种输入:
function([1,2,3,4])
function("foo")
function("foo".chars)
至于函数的正确性,您可以使用测试,而不是编译器。但这是另一个主题。 :)
答案 2 :(得分:2)
考虑到Ruby是动态类型的,你不能以类似的方式强制执行,例如在C中。而不是与字符串进行比较,你实际上可以将它与类进行比较。
arg.is_a?(Array)
为了改进你的例子我会写:
def function(arg)
raise TypeError unless arg.is_a?(Array)
# Do stuff
end
答案 3 :(得分:1)
Ruby不支持类型检查 - 至少,不能将参数类型声明为方法签名的一部分。通常,调用者负责传递正确的对象,或者传递的对象负责转换自己。但是,你当然可以做自己的强制。事实上,about.com有an example使用case语句进行这种类型检查。
以下是一些其他示例:
# Ask your object to convert itself to an array.
def foo my_object
my_object.to_a
end
# Give your object a #to_a method if it doesn't already have one.
def foo my_object
unless my_object.respond_to? :to_a
def my_object.to_a
# perform your type conversion
end
end
end
# Do your own type conversions.
def foo my_object
case my_object
when Array
p my_object
when String
my_object.scan /\d+/
end
end
你可以混合搭配任何这些技巧,当然也有其他技术。 Ruby是一种非常灵活的语言。
答案 4 :(得分:0)
除了引发错误,您可以确定将参数转换为数组,但您应该在提供参数的例程中工作,以便首先为您提供数组。
def function(*arg)
a = arg.flatten
p a
end
function("ab")
function(1,2)
function([1,2])
#=>
#["ab"]
#[1, 2]
#[1, 2]
答案 5 :(得分:0)
如果你的例子中的接收器是微不足道的,并且它被定义为函数而不是方法,那么,你可能想要将参数转换为接收器。
class Array
def function
# do stuff
end
end