instance_of
语句,以检查并在各处增加运行时错误,这很丑陋。必须有更好的方法。
我的个人方式(我不确定这是否是建议的方式)是在发生错误后进行类型检查并进行其他验证。我将类型的检查例程放在救援块中。这样,当给出正确的参数时,我可以避免绩效丧失,但是在发生错误时仍会退还正确的错误消息。
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
在each
arg1
假设arg1
是一个数组。如果事实证明它是其他的,而不是定义
each
,则裸露的错误消息将是类似
method each not defined on ...
,从方法的使用者的角度来看,这可能不是有帮助。在这种情况下,原始错误消息将被消息
foo
替换,这更有帮助。
当然,ruby是动态键入的。方法文档确定类型合同;类型信息从正式的类型系统转移到[方法文档中的非正式类型规范。我将诸如“阵列”和“是字符串”之类的细节之类的概述混合在一起。呼叫者只能期望与
stated类型一起使用。
如果呼叫者违反了此合同,那么任何事情都可能发生。该方法不必担心:它被错误地使用。
在上述情况下,iAvoid检查特定类型,并试图以这种行为来创建过载。 lunit检验可以确保合同适用于预期数据。
如果编写了合理的测试,则所有内容都将被称为。
如果每个方法都被调用,则每个方法都会被键入检查。不要将浪费时间放入可能不必要地限制呼叫者的类型检查中,并且无论如何都会复制运行时检查。花时间编写测试。
我建议在方法开头使用加薪来添加手动类型检查,简单有效:
Expecting an array: ...
加:您可以使用自定义异常
def foo(bar)
raise TypeError, "You called foo without the bar:String needed" unless bar.is_a? String
bar.upcase
end
您可以使用contracts方法使用theContractsRubyGem进行设计。我觉得很好。
您可以手动检查参数的类型并在错误的情况下引起错误。
class NotStringError < TypeError
def message
"be creative, use metaprogramming ;)"
#...
raise NotStringError
用鸭子打字
启用检查特定类别,您可以检查对象是否响应所需的方法。
raise
使用Ruby 3的类型签名(RB)
respond_to?
使用is_a?还是响应_to?用于运行时类型检查。使用Ruby 3的RB用于静态执行。 使用更严格的运行时类型检查。