我如何只允许Ruby函数中的参数成为某种类型?

时间:2012-05-30 21:09:28

标签: ruby function parameters arguments

例如,如果我有

def function(arg)
  #do stuff
end

我如何才允许arg成为数组?我能做到

def function(arg)
  if arg.class != 'Array'
    return 'Error'
  else
    #do stuff
  end
end

但有没有更好的方法呢?

6 个答案:

答案 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