12

私の質問はこの質問に基づいています:Ruby Koan:定数はシンボルになります。私は次のコードを持っています:

in_ruby_version("mri") do
  RubyConstant = "What is the sound of one hand clapping?"
  def test_constants_become_symbols
    all_symbols = Symbol.all_symbols

    assert_equal __, all_symbols.include?(__)
  end
end

正解は次のようになっていますか?

    assert_equal true, all_symbols.include?("RubyConstant".to_sym)

私はこれをするべきではないことを知っています:

    assert_equal true, all_symbols.include?(:RubyConstant)

それなら私はそこに何でも入れることができましたそしてそれはまだ本当でしょう

    assert_equal true, all_symbols.include?(:DoesNotMatter)

簡単な「はい」または「いいえ」の質問をすることについて、事前に謝罪します。私は「正しい」答えが何であるかを知りたいと思いました。私は上記の前の投稿のコメントでこの質問をすることを好んだでしょうが、私は別の投稿をしなければできませんでした。

4

3 に答える 3

12

これが私が得たものです:

in_ruby_version("mri") do
  RubyConstant = "What is the sound of one hand clapping?"
  def test_constants_become_symbols
    all_symbols_as_strings = Symbol.all_symbols.map { |x| x.to_s }

    assert_equal true, all_symbols_as_strings.include?("RubyConstant")
  end
end
于 2013-12-13T09:11:20.090 に答える
5

Symbol.all_symbols参照されたすべてのシンボル(変数名、クラス名、定数名、実際のシンボル)が含まれます。この変数に実際に含まれているのは実装定義ですが、Ruby MRIでは、多くのシンボルがすでにこのリストに含まれています。

irb(main):001:0> Constant = 42
=> 42
irb(main):002:0> Symbol.all_symbols
=> [:"", :"<IFUNC>", :"<CFUNC>", :respond_to?,  ..., :irb_exit_org, :Constant]

しかし、今、落とし穴があります。

Symbol.all_symbols.include?(:DoesNotMatter)

このコードを実行する前に、に:DoesNotMatterは存在しませんが、all_symbolsどういうわけかまだ存在しています。ええと、実際にシンボルリテラルを使用するとき、それはに挿入されますSymbol.all_symbols(すでにそこにある場合を除く)。したがって、を呼び出す前に、シンボルはすでにここにあります.include?

編集:グレゴリーブラウンは次の回避策を提案しました。これは、RubySymbol.all_symbolsでは、変数への参照をコピーする代わりに、何らかの理由で変数をコピーするために機能します。

irb(main):001:0> symbols = Symbol.all_symbols; 1
=> 1
irb(main):002:0> symbols.include? :something
=> false
irb(main):003:0>
于 2012-11-08T19:02:57.777 に答える
5

注:次の回答は、Rubyコードが1行ずつ実行されているirbなどの環境にのみ適用されます。ファイル内のコードを実行する場合、Rubyは何かを実行する前にファイル全体をスキャンしてシンボルを探すため、以下の詳細は正確ではありません。この回答は興味深いエッジケースを示しているため削除していませんが、問題のより適切な説明については@GlichMrの回答を参照してください。

Symbol.all_symbols参照ではなくシンボルの配列のコピーを返すため、次のことを安全に行うことができます。

assert_equal true, all_symbols.include?(:RubyConstant)

それが公案に対する意図された答えだと思います。それが、直接all_symbols呼び出すのではなく、定義されている理由です。Symbol.all_symbolsいくつかの証拠については、以下を参照してください。

>> X = 1
=> 1
>> all_symbols = Symbol.all_symbols; nil
=> nil
>> Y = 2
=> 2
>> all_symbols.include?(:X)
=> true
>> all_symbols.include?(:Y)
=> false

を使用すると、これらの呼び出しを直接String#to_sym行うことができますが、この公案を解決するために必要ではありません。Symbol.all_symbols

于 2012-11-08T23:48:58.400 に答える