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 は動的に型付けされます。
したがって、メソッドのドキュメントによって型コントラクトが決定されます。型情報は、形式的な型システムから [非形式的な] メソッド ドキュメントに移動されます。「配列のように振る舞う」などの一般論と、「文字列である」などの詳細を混ぜ合わせます。呼び出し元は、指定された型でのみ動作することを期待する必要があります。
呼び出し元がこの契約に違反した場合、何かが起こる可能性があります。このメソッドは心配する必要はありません。使用方法が間違っていました。
上記に照らして、特定の型をチェックすることを避け、そのような動作でオーバーロードを作成しようとすることを避けます。
単体テストは、期待されるデータに対してコントラクトが機能することを確認するのに役立ちます。
メソッドが存在する理由がある場合、メソッドが呼び出されます。
合理的なテストが書かれていれば、すべてが呼び出されます。
そして、すべてのメソッドが呼び出されると、すべてのメソッドが型チェックされます。
呼び出し元を不必要に制約する可能性があり、実行時チェックを複製するだけの型チェックを入れて時間を無駄にしないでください。代わりに、その時間をテストの作成に費やしてください。
コントラクトruby gemを使用して、 Design by Contractアプローチを使用できます。とてもいいと思います。