Rubyのダブルコロン `::`とは何ですか?


427

このダブルコロンは何::ですか?例えばFoo::Bar

私は定義を見つけました:

::定数、インスタンスメソッドとクラスメソッドは、クラスまたはモジュールの外部の任意の場所からアクセスする、クラスまたはモジュール内で定義:可能単項演算子です。

何か::を公​​開するためだけに使用できる場合、スコープ(プライベート、保護)はどのように役立ちますか?


175
将来のグーグルの利益のために、シンボルを検索する場合は、symbolhound.comを
Andrew Grimm

1
重複の可能性はありますか?stackoverflow.com/questions/2276905/what-does-mean-in-ruby
iX3


6
@AndrewGrimmさん、祝福を。それが今週見た中で最高です。
アベガー2014

回答:


381

::基本的には名前空間解決演算子です。モジュール内のアイテム、またはクラス内のクラスレベルのアイテムにアクセスできます。たとえば、次の設定があるとします。

module SomeModule
    module InnerModule
        class MyClass
            CONSTANT = 4
        end
    end
end

CONSTANTモジュールの外部からとしてアクセスできますSomeModule::InnerModule::MyClass::CONSTANT

異なる構文(ドット.)でアクセスするため、クラスで定義されたインスタンスメソッドには影響しません。

関連する注記:トップレベルのネームスペースに戻りたい場合は、次のようにします。:: SomeModule – Benjamin Oakes


5
たとえばC#では、はい。一方、C ++(およびRuby)は::、次のような名前空間の解決に使用されますstd::cout << "Hello World!";
Jerry Fernholz

142
関連注記:あなたはトップレベルの名前空間に戻したい場合は、この操作を行います。 ::SomeModule
ベンジャミンオークス

5
@Benjaminたまたま別のモジュールの中にSomeModuleがあり、代わりにトップレベルのモジュールを取得したい場合を除いて、先頭のコロンが暗黙に含まれていますか?
Jo Liss

7
@Joはい。トップレベルの名前空間の定数、または別のモジュール内の同じ名前の定数(:: SomeOtherModule :: ClassMethodsなど)を参照していることを確認する場合に役立ちます。
ベンジャミンオークス

2
これはC ++のスコープオペランドと非常によく似ています
lkahtz

111

この簡単な例はそれを示しています:

MR_COUNT = 0        # constant defined on main Object class
module Foo
  MR_COUNT = 0
  ::MR_COUNT = 1    # set global count to 1
  MR_COUNT = 2      # set local count to 2
end

puts MR_COUNT       # this is the global constant: 1
puts Foo::MR_COUNT  # this is the local constant: 2

http://www.tutorialspoint.com/ruby/ruby_operators.htmから取得


これが警告の原因です。警告を回避する方法はありますか?
NullVoxPopuli 2013年

3
@NullVoxPopuli一般に定数を変更することは本当に悪いことですが、たとえば、不適切に記述されたgemの定数を変更してフォークしたくない場合は、.send(:remove_const)を使用して、その後、定数を再定義します。
BookOfGreg

71

::別のクラスまたはモジュール内で定義された定数、モジュール、またはクラスにアクセスできます。名前空間を提供するために使用され、メソッドやクラス名が異なる作成者による他のクラスと競合しないようにします。

ActiveRecord::BaseRailsで見ると、それはRailsが次のようなものを持っていることを意味します

module ActiveRecord
  class Base
  end
end

つまり、次に参照されるBaseモジュール内で呼び出されるクラス(これは、Railsソースのactiverecord-nnn / lib / active_record / base.rbにあります)ActiveRecordActiveRecord::Base

::の一般的な用途は、モジュールで定義された定数にアクセスすることです。

module Math
  PI = 3.141 # ...
end

puts Math::PI

::オペレータは、プライベートとマークまたは保護されたメソッドのバイパス視界にあなたを許可していません。


7
ではclass MyClass < ActiveRecord::Base、がある場合、それはMyClassがクラスベースからのメソッドのみを継承し、ActiveRecordモジュール内には何も継承しないことを意味しますか?
チャーリーパーカー

2
この名前空間の解決に、「。」を使用するのではなく、特別な二重コロンを使用する理由 これも?「。」を使用していても、文脈と大文字化は意味の混乱を防ぐでしょうね。
ジョナ

3
@ジョナがあいまいになる場合があります。たとえば、class Foo; Baz = 42; def self.Baz; "Baz method!"; end; end(完全に有効)Foo::Baz # => 42およびを検討してくださいFoo.Baz # => "Baz method!"Foo::Baz()(括弧付きで)メソッドを呼び出すことにも注意してください。
mikej

3
それで、ユースケースはそれを解決して、まったく同じ名前を持つクラス定数とクラスメソッドを持つ能力を解決しますか?それは機能を支持する強い議論のようには思えません。個人的には、どちらかと言えばその能力を失い(とにかくトラブルのようです)、ダブルコロンを失って、「。」を使用します。名前空間についても....多分それが解決する追加のユースケースがありますか?
ジョナ

26

::を使用して何かを公開できる場合、スコープ(プライベート、保護)はどのように役立ちますか?

Rubyでは、すべてが公開されており、他の場所からすべてを変更できます。

「クラス定義」の外側からクラスを変更できるという事実を心配しているのであれば、Rubyはおそらくあなたには向いていません。

一方、Javaのクラスがロックダウンされていることに不満を感じている場合は、Rubyがおそらく探しているものです。


1
一部のルビイストは、インスタンス変数は公開されておらず、attr_accessor単に変数を変更するメソッドを作成するだけだと言うのを聞いたことがあります。(その後、再びありますinstance_eval
Andrew Grimm

4
正解instance_evalです。しかしinstance_variable_get、ともありinstance_variable_setます。Rubyは制約に対して動的すぎます。
yfeldblum

12

以前の回答に加えて、::インスタンスメソッドへのアクセスに使用するのは有効なRubyです。次のすべてが有効です。

MyClass::new::instance_method
MyClass::new.instance_method
MyClass.new::instance_method
MyClass.new.instance_method

ベストプラクティスに従って、最後の1つだけが推奨されると思います。


11

いいえ、すべてのメソッドにアクセスするのではなく、「解決」演算子です。つまり、これを使用して、定数/静的シンボルのスコープ(または言うことができる場所)を解決します。

たとえば、最初の行では、Railsはそれを使用してActiveRecord.Module内のBaseクラスを検索し、2番目の行ではRoutesクラスのクラスメソッド(静的)を検索するために使用されます。

何かを公開するために使用されるのではなく、スコープの周りにあるものを「見つける」ために使用されます。

http://en.wikipedia.org/wiki/Scope_resolution_operator


「(static)」とは「(draw)」を意味しますか?!?
Meltemi

8

驚いたことに、ここでの10の回答はすべて同じことを言っています。'::'は名前空間解決演算子であり、そうです。しかし、定数ルックアップアルゴリズムに関しては、名前空間解決演算子について理解しなければならない1つの問題があります。Matzが彼の著書「Rubyプログラミング言語」で描写しているように、定数ルックアップには複数のステップがあります。まず、定数が参照されているレキシカルスコープで定数を検索します。字句スコープ内で定数が見つからない場合は、継承階層を検索します。この定数ルックアップアルゴリズムのため、以下は期待される結果になります。

module A
  module B
      PI = 3.14
      module C
        class E
          PI = 3.15
        end
        class F < E
          def get_pi
            puts PI
          end
        end
      end
  end
end
f = A::B::C::F.new
f.get_pi
> 3.14

FはEから継承しますが、BモジュールはFの字句スコープ内にあります。したがって、FインスタンスはモジュールBで定義された定数PIを参照します。モジュールBがPIを定義しなかった場合、FインスタンスはPIを参照しますスーパークラスEで定義されている定数。

しかし、ネストモジュールではなく「::」を使用するとどうなるでしょうか。同じ結果が得られますか?番号!

ネストされたモジュールを定義するときに名前空間解決演算子を使用することにより、ネストされたモジュールとクラスは、それらの外部モジュールの字句スコープ内になくなります。以下に示すように、A :: Bで定義されたPIはA :: B :: C :: Dのレキシカルスコープにないため、get_piインスタンスメソッドでPIを参照しようとすると、初期化されていない定数を取得します。

module A
end

module A::B
  PI = 3.14
end

module A::B::C
  class D
    def get_pi
      puts PI
    end
  end
end
d = A::B::C::D.new
d.get_pi
NameError: uninitialized constant A::B::C::D::PI
Did you mean?  A::B::PI

4

それはすべて、定義がプロジェクトにリンクされている他のコードと衝突しないようにすることです。つまり、物事を分離しておくことができます。

たとえば、コードに「run」という1つのメソッドを含めることができ、リンクした他のライブラリで定義されている「run」メソッドではなく、メソッドを呼び出すことができます。


3
module Amimal
      module Herbivorous
            EATER="plants" 
      end
end

Amimal::Herbivorous::EATER => "plants"

::スコープの作成に使用されます。2つのモジュールから定数EATERにアクセスするには、定数に到達するようにモジュールをスコープする必要があります


3

Ruby on Railsは::名前空間の解決に使用します。

class User < ActiveRecord::Base

  VIDEOS_COUNT = 10
  Languages = { "English" => "en", "Spanish" => "es", "Mandarin Chinese" => "cn"}

end

それを使用するには:

User::VIDEOS_COUNT
User::Languages
User::Languages.values_at("Spanish") => "en"

また、他の使用法:ネストされたルートを使用する場合

OmniauthCallbacksController ユーザーの下で定義されます。

そして次のようにルーティングされます:

devise_for :users, controllers: {omniauth_callbacks: "users/omniauth_callbacks"}


class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController

end
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.