由于 ruby 中没有类型,Ruby 程序员如何确保函数接收正确的参数?现在,我在到处重复if object.kind_of
/语句来检查和引发运行时错误,这很丑陋。instance_of
必须有更好的方法来做到这一点。
5 回答
我个人的方式(我不确定这是否是一般推荐的方式)是在发生错误时进行类型检查并进行其他验证。我将类型检查程序放在救援块中。这样,当给出正确的参数时,我可以避免性能损失,但在发生错误时仍然返回正确的错误消息。
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 ,这会更有帮助。arg1
arg1
each
method each not defined on ...
foo
Expecting an array: ...
当然,Ruby 是动态类型的。
因此方法文档决定了类型契约;类型信息从正式类型系统移动到 [informal type specification in the] 方法文档。我混合了诸如“像数组一样行为”之类的一般性和诸如“是一个字符串”之类的细节。调用者应该只期望使用指定的类型。
如果调用者违反了这个契约,那么任何事情都可能发生。该方法不必担心:它使用不正确。
鉴于上述情况,我避免检查特定类型并避免尝试创建具有此类行为的重载。
单元测试可以帮助确保合约适用于预期数据。
如果一个方法有存在的理由,它就会被调用。
如果编写了合理的测试,一切都会被调用。
如果每个方法都被调用,那么每个方法都会被类型检查。
不要浪费时间进行类型检查,这可能会不必要地限制调用者并且无论如何都会重复运行时检查。而是花时间编写测试。
我推荐在方法开头使用 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