これについてわかったとき、私は値のシリアル化に取り組んでいました。 Rubyには TrueClass
クラスと FalseClass
クラスがありますが、Boolean
クラスです。これがなぜなのか知りたいのですが。
Boolean
を使用することにはいくつかの利点があります。たとえば、文字列の構文解析を一元化できます。
Ruby開発者は私より頭が良いので、私が見ないだけの理由はたくさんあるに違いありません。しかし、今のところ、 OneClass
の代わりにTwoClass
とFixnum
を持っているように見えます。
マッツ自身が2004年に メーリングリストメッセージ でこの質問に回答したようです。
彼の答えの短いバージョン:「現時点では問題なく動作し、ブール値を追加してもメリットはありません。」.
個人的には私はそれに同意しません。前述の「文字列解析」はその一例です。もう1つは、「ブール」クラスを持つ変数(ymlパーサーなど)に応じて変数に異なる処理を適用する場合に便利です。1つの「if」が削除されます。見た目もより正確ですが、それは個人的な意見です。
クラスの目的は、類似したオブジェクト、または類似した動作を持つオブジェクトをグループ化することです。 1
と2
は非常に似ているため、同じクラスに属していることは完全に理にかなっています。 true
とfalse
は似ていますが似ていません。実際、それらの全体は、それらが正確に互いに反対であり、反対の動作をするということです。したがって、それらは同じクラスに属していません。
Boolean
クラスに実装する一般的な動作の例を挙げていただけますか?何も考えられない。
TrueClass
とFalseClass
の振る舞いを見てみましょう。正確にfourメソッドがあります。もういや。そして、すべての単一のケースで、2つのメソッドは正確に反対を行います。どのようにそしてなぜあなたはそれを単一のクラスに入れますか?
これらのメソッドをすべて実装する方法は次のとおりです。
class TrueClass
def &(other)
other
end
def |(_)
self
end
def ^(other)
!other
end
def to_s
'true'
end
end
そして今、その逆です:
class FalseClass
def &(_)
self
end
def |(other)
other
end
def ^(other)
other
end
def to_s
'false'
end
end
確かに、Rubyでは舞台裏で起こっている多くの「魔法」があり、実際にはTrueClass
とFalseClass
によって処理されるのではなく、インタープリターに組み込まれています。 if
、&&
、||
、!
など。ただし、Smalltalkでは、RubyがFalseClass
およびTrueClass
の概念を含めて多くを借用しました)では、これらすべてがメソッドとしても実装されており、 Rubyでも同じことができます。
class TrueClass
def if
yield
end
def ifelse(then_branch=->{}, _=nil)
then_branch.()
end
def unless
end
def unlesselse(_=nil, else_branch=->{})
ifelse(else_branch, _)
end
def and
yield
end
def or
self
end
def not
false
end
end
そして再びその逆:
class FalseClass
def if
end
def ifelse(_=nil, else_branch=->{})
else_branch.()
end
def unless
yield
end
def unlesselse(unless_branch=->{}, _=nil)
ifelse(_, unless_branch)
end
def and
self
end
def or
yield
end
def not
true
end
end
数年前、私は楽しみのために上記を書き、 公開されていても を書きました。 Rubyはメソッドのみを使用しながら特殊な演算子を使用するため、構文が異なるという事実は別として、Rubyの組み込み演算子とまったく同じように動作します。実際、実際には RubySpec準拠testsuite と 私の構文に移植 とパスします。
trueとfalseは、複数の値を保持するブールクラスで管理できますが、その場合、クラスオブジェクトは内部値を持つ必要があるため、使用するたびに逆参照する必要があります。
代わりに、Rubyは、trueとfalseを長い値(0と1)として扱います。それぞれの値は、オブジェクトクラスのタイプ(FalseClassとTrueClass)に対応します。単一のブール値の代わりに2つのクラスを使用することによってクラス、各クラスは値を必要としないため、そのクラス識別子(0または1)によって簡単に区別できます。これは、Rubyエンジンの内部で速度が大幅に向上することにつながります。 Rubyは、TrueClassとFalseClassを、ID値からのゼロ変換を必要とする長い値として扱うことができますが、ブールオブジェクトは、評価する前に逆参照する必要があります。
Rubyフォーラム(2013) でMatzを引用:
... trueとfalseが共通に共有するものは何もないため、ブールクラスはありません。それ以外に、Rubyではすべてがブール値として動作します...
false
とnil
以外はすべてデフォルトでRuby)でtrueに評価されるため、Stringに解析を追加するだけで済みます。
このような何かがうまくいくかもしれません:
class Object
## Makes sure any other object that evaluates to false will work as intended,
## and returns just an actual boolean (like it would in any context that expect a boolean value).
def trueish?; !!self; end
end
class String
## Parses certain strings as true; everything else as false.
def trueish?
# check if it's a literal "true" string
return true if self.strip.downcase == 'true'
# check if the string contains a numerical zero
[:Integer, :Float, :Rational, :Complex].each do |t|
begin
converted_number = Kernel.send(t, self)
return false if converted_number == 0
rescue ArgumentError
# raises if the string could not be converted, in which case we'll continue on
end
end
return false
end
end
使用すると、次のようになります。
puts false.trueish? # => false
puts true.trueish? # => true
puts 'false'.trueish? # => false
puts 'true'.trueish? # => true
puts '0'.trueish? # => false
puts '1'.trueish? # => true
puts '0.0'.trueish? # => false
puts '1.0'.trueish? # => true
Ruby=の背後にある「大きなアイデア」の一部は、独自のネームスペースに存在する完全にカプセル化されたクラスを作成するのではなく、希望する動作をプログラムに固有のものにすることです(ブール解析など)。ワールド(例:BooleanParser)。
Ruby nilとfalseはfalseであり、その他はすべてtrueであるため、特定のブールクラスは必要ありません。
あなたはそれを試すことができます :
if 5
puts "5 is true"
end
5はtrueと評価されます
if nil
puts "nil is true"
else
puts "nil is false"
end
「nil is false」を出力します
主な理由は、ブール式を実装するほうが、変換を意味するブールクラスを使用する場合よりもはるかに速く簡単であることです。
Mongus Pongが言ったように、 "if"と書くと、インタプリタにthingを評価してから分岐するように依頼します。ブールクラスがあった場合、評価thingをブールbeforeブランチに変換する必要があります(もう1ステップ)。
このような->ブール変換は、ブールクラスのRubyメソッドとして使用できます。このメソッドは、他のRubyメソッドと同様に動的に変更できます。 、開発者が物事を完全に台無しにすることを許可します(実際にはそれほど深刻ではありません)。
Ruby( "send"メソッドの処理を思い出してください)...).