Rubyでの素朴なニル処理
過去6か月ほどの間、私はRustでNESエミュレーターを使用してきました。ご想像のとおり、私はさびについて多くのことを学び、さらにNESの内部についても学びました。しかし、その経験によって、Rubyの見方も変わりました。
具体的には、nil
を返すメソッドについて少し妄想的になりました。 。
何かを支持しないと、何にでも落ちる
nil
とは Rubyの意味ですか?ほとんど何でも。メソッドがnilを返す場合、それは次のことを意味する可能性があります:
- メソッドには戻り値がありません
- 通常は戻り値がありますが、今回はありません
- データベースからNULLの値を返します
- 予期しないことが起こりました
これによりコードが読みにくくなり、最も一般的なの主な原因になります。 RubyのRuby例外:NoMethodError
。例外監視サービスの一部所有者として、NoMethodError
私の子供を学校に通わせています。
次のコードを見てください。 nil
を返します ほとんどの場合、if
ステートメントはnil
と評価されます 条件が一致せず、else
がない場合 。
def color_name(rgb)
if rgb == 0x000000
"black"
end
end
color_name("#FFFFFF").titleize
=> NoMethodError: undefined method `titleize' for nil:NilClass
経験豊富なRuby開発者であれば、このうさぎの穴がさらに深くなることをご存知でしょう。 nilのこれらの異なる意味が奇妙な方法で重複することがあり、たとえば、データベースの値がNULL
であるかどうかを知ることができなくなります。 、またはデータベースに値がまったくありません。
Rustには、nil
のようなものはありません。 。代わりに、関数が値を返す場合と「何も返さない」場合があることを示したい場合は、Option
を使用します。 。
Options
特定の値を含むか、値を含まないタイプです。コードでの表示は次のとおりです。
Option::Some(42); // Wraps the number 42 in an option
Option::None; // Indicates "no result"
これは、アドホックなnil
よりもすでに良く見えています 使用法ですが、それはさらに良くなります。 Rustコンパイラは、None
を考慮するように強制します 場合。誤って無視することはできません。
match my_option {
Some(x) => do_something_with_x(x),
// If you remove the `None` match below, this code
// won't compile.
None => do_the_default_thing()
}
したがって、色の命名例を次のように錆びた形で書くことができます:
fn color_name(rgb: u32) -> Option<String> {
if rgb == 0x000000 {
Some("black".to_owned())
} else {
None
}
}
今、私たちは両方のSome
を処理することを余儀なくされています およびNone
条件:
let name = color_name(0xFFFFFF);
let name = match color_name(0xFFFFFF) {
Some(value) => value,
None => "unknown".to_owned(),
}
確かにこれは少し冗長で奇妙な見た目ですが、関数が有用な値を返さない場合を無視することはできません。つまり、理解と保守が容易なコードを意味します。
Rubyが厳密さに欠けているものは、柔軟性で補います。 Option
のようなものを実装してみるのは面白いと思いました Rubyで。
Rubyはインタプリタ言語であるため、コンパイル時エラーを作成することはできません。ただし、誤ったコードが常に発生する可能性があります エッジケースに遭遇したときにのみ例外を発生させるのではなく、例外を発生させます。
まず、2つのクラスを作成しましょう。 Some
読み取り専用の値を保持します。 None
空です。見た目と同じくらいシンプルです。
class Some
attr_reader :value
def initialize(value)
@value = value
end
end
class None
end
次に、Option
を作成します Some
のいずれかを保持するクラス またはNone
両方にハンドラーを提供する場合にのみ、それらにアクセスできます。
class Option
def initialize(value)
@value = value
end
def self.some(value)
self.new(Some.new(value))
end
def self.none()
self.new(None.new)
end
def match(some_lambda, none_lambda)
if @value.is_a?(Some)
some_lambda.call(@value.value)
elsif @value.is_a?(None)
none_lambda.call()
else
raise "Option value must be either Some or None"
end
end
end
最後に、新しいOption
を使用するように色の例を書き直すことができます。 クラス:
def color_name(rgb)
if rgb == 0x000000
Option.some("black")
else
Option.none()
end
end
puts color_name(0x000000).match(
-> value { value },
-> { "no match" })
# Prints "black"
私はまだ実際のプロジェクトでこのテクニックを試していません。多くのNoMethodErrors
を確実に防ぐことができると思います それは常に生産に滑り込みます。見た目は少し面倒で、あまりルビーっぽくはありませんが、少し改良すれば、より快適な構文ができると思います。
-
Rubyでのラムダの使用
ブロックはRubyの非常に重要な部分であり、ブロックなしで言語を想像するのは難しいです。しかし、ラムダ?ラムダが好きなのは誰ですか?あなたはそれを使わずに何年も行くことができます。まるで過ぎ去った時代の遺物のようです。 ...しかし、それは完全に真実ではありません。ラムダを少し調べてみると、ラムダにはいくつかの興味深いトリックがあります。 この記事では、ラムダの使用法の基本から始めて、さらに興味深い高度な使用法に移ります。したがって、ラムダを毎日使用していて、それらについてすべて知っている場合は、下にスクロールするだけです。 Lambdasについて覚えておくべき主なことは、それらが関数の
-
Ruby2.6の9つの新機能
Rubyの新しいバージョンには、新しい機能とパフォーマンスの改善が含まれています。 変更についていきますか? 見てみましょう! 無限の範囲 Ruby 2.5以前のバージョンは、すでに1つの形式の無限範囲をサポートしています( Float ::INFINITY を使用) )、しかしRuby2.6はこれを次のレベルに引き上げます。 新しい無限の範囲 次のようになります: (1..) これは、(1..10)のような終了値がないため、通常の範囲とは異なります。 。 使用例 : [a, b, c].zip(1..) # [[a, 1], [b, 2], [c, 3]] [1,2,3,