25

由于 ruby​​ 中没有类型,Ruby 程序员如何确保函数接收正确的参数?现在,我在到处重复if object.kind_of/语句来检查和引发运行时错误,这很丑陋。instance_of必须有更好的方法来做到这一点。

4

5 回答 5

24

我个人的方式(我不确定这是否是一般推荐的方式)是在发生错误时进行类型检查并进行其他验证。我将类型检查程序放在救援块中。这样,当给出正确的参数时,我可以避免性能损失,但在发生错误时仍然返回正确的错误消息。

def foo arg1, arg2, arg3
  ...
  main_routine
  ...
rescue
  ## check for type and other validations
  raise "Expecting an array: #{arg1.inspect}" unless arg1.kind_of?(Array)
  raise "The first argument must be of length 2: #{arg1.inspect}" unless arg1.length == 2
  raise "Expecting a string: #{arg2.inspect}" unless arg2.kind_of?(String)
  raise "The second argument must not be empty" if arg2.empty?
  ...
  raise "This is `foo''s bug. Something unexpected happened: #{$!.message}"
end

假设在 中main_routine,您使用假设它是一个数组的方法each。如果事实证明它是未定义的其他东西,那么裸露的错误消息将类似于,从方法用户的角度来看,这可能没有帮助。在这种情况下,原始错误消息将被替换为 message ,这会更有帮助。arg1arg1eachmethod each not defined on ...fooExpecting an array: ...

于 2012-03-22T06:03:28.193 回答
19

当然,Ruby 是动态类型的。

因此方法文档决定了类型契约;类型信息从正式类型系统移动到 [informal type specification in the] 方法文档。我混合了诸如“像数组一样行为”之类的一般性和诸如“是一个字符串”之类的细节。调用者应该只期望使用指定的类型。

如果调用者违反了这个契约,那么任何事情都可能发生。该方法不必担心:它使用不正确。

鉴于上述情况,我避免检查特定类型并避免尝试创建具有此类行为的重载。

单元测试可以帮助确保合约适用于预期数据。

于 2012-03-22T05:45:02.657 回答
9

如果一个方法有存在的理由,它就会被调用。

如果编写了合理的测试,一切都会被调用。

如果每个方法都被调用,那么每个方法都会被类型检查。

不要浪费时间进行类型检查,这可能会不必要地限制调用者并且无论如何都会重复运行时检查。而是花时间编写测试。

于 2012-03-22T06:06:16.920 回答
2

我推荐在方法开头使用 raise 来添加手动类型检查,简单有效:

def foo(bar)
    raise TypeError, "You called foo without the bar:String needed" unless bar.is_a? String
    bar.upcase
end

当您没有太多参数时,最好的方法是使用 ruby​​ 2+ 上可用的关键字参数,如果您有多个参数并注意其当前/未来的实现细节,它们正在改善这种情况,为程序员提供了一种方法查看该值是否为零。

加:您可以使用自定义异常

class NotStringError < TypeError
   def message 
     "be creative, use metaprogramming ;)"
#...
raise NotStringError
于 2013-12-21T05:43:00.063 回答
1

您可以使用 Contracts ruby​​ gem 的Design by Contract方法。我觉得挺好看的。

于 2016-07-01T02:55:25.810 回答