6

例如,如果我有

def function(arg)
  #do stuff
end

我如何只允许arg成为一个数组?我可以做

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

但是有没有更好的方法呢?

4

6 回答 6

11

您不能 def function(Array arg)像其他语言那样做,但是您可以将第二个代码段的四行替换为一行:

def function(arg)
  raise TypeError unless arg.is_a? Array
  # code...
end
于 2012-05-30T21:14:54.643 回答
6

其他人指出了如何在技术上强制执行某种类型的论点,但你正在与红宝石思维方式进行一场根本性的战斗。谷歌搜索“鸭子打字”。

在 ruby​​ 世界中,我们通常不关心参数的类型,而是关心它是否满足我们想要用它做的接口。换句话说,它像鸭子一样嘎嘎叫吗?够好了!

假设您正在尝试将 Array 用于某事:

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)

至于函数的正确性,您使用测试而不是编译器来覆盖它。但那完全是另一回事了。:)

于 2012-05-30T21:50:16.093 回答
2

很好地考虑到 Ruby 是动态类型的,您不能以类似的方式强制执行它,例如在 C 中。您实际上可以将它与类进行比较,而不是与字符串进行比较。

arg.is_a?(Array)

为了改进你的例子,我会写:

 def function(arg)
   raise TypeError unless arg.is_a?(Array)
   # Do stuff
 end
于 2012-05-30T21:14:36.597 回答
1

Ruby 不支持类型检查——至少,不能将参数类型声明为方法签名的一部分。一般来说,调用者负责传递正确的对象,或者传递的对象负责转换自己。但是,您当然可以进行自己的强制。事实上,about.com 有一个使用 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 是一种非常灵活的语言。

于 2012-05-30T21:49:16.350 回答
0

您可以确定将参数转换为数组,而不是引发错误,但您应该在提供参数的例程中工作,以便它首先为您提供数组。

def function(*arg)
  a = arg.flatten
  p a
end

function("ab")
function(1,2)
function([1,2])

#=>
#["ab"]
#[1, 2]
#[1, 2]
于 2012-05-30T22:27:46.970 回答
0

如果您的示例中的接收器是微不足道的,并且它被定义为函数而不是方法,那么您可能希望将参数转换为接收器。

class Array
  def function
    # do stuff
  end
end
于 2012-05-31T04:54:14.917 回答