Qual è il doppio punto di Ruby `::`?


427

Cos'è questo doppio colon ::? Es Foo::Bar.

Ho trovato una definizione :

La ::è un operatore unario che permette: costanti, metodi di istanza e metodi di classe definiti all'interno di una classe o modulo, a cui accedere da qualsiasi posizione esterna alla classe o modulo.

A che serve l'ambito (privato, protetto) se puoi semplicemente usare ::per esporre qualcosa?


175
A beneficio dei futuri googler, se stai cercando un simbolo, prova a symbolhound.com
Andrew Grimm,



6
Ti benedica, @AndrewGrimm. Questa è la cosa migliore che ho visto questa settimana.
abeger,

Risposte:


381

::è fondamentalmente un operatore di risoluzione dello spazio dei nomi. Consente di accedere agli elementi nei moduli o agli elementi a livello di classe nelle classi. Ad esempio, supponi di avere questa configurazione:

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

È possibile accedere CONSTANTdall'esterno del modulo come SomeModule::InnerModule::MyClass::CONSTANT.

Non influisce sui metodi di istanza definiti su una classe, poiché accedi a quelli con una sintassi diversa (il punto .).

Nota pertinente: se si desidera tornare allo spazio dei nomi di livello superiore, procedere come segue: :: SomeModule - Benjamin Oakes


5
In C #, ad esempio, sì. D'altra parte C ++ (e Ruby) usano ::per la risoluzione dello spazio dei nomi comestd::cout << "Hello World!";
Jerry Fernholz,

142
Nota pertinente: se si desidera tornare allo spazio dei nomi di livello superiore, procedere come segue: ::SomeModule
Benjamin Oakes,

5
@Benjamin I due punti principali sono impliciti, a meno che non mi capiti di avere un SomeModule all'interno di un altro modulo e non voglio ottenere quello di livello superiore, giusto?
Jo Liss,

7
@Jo Sì. Può essere utile se vuoi assicurarti di riferirti a una costante nello spazio dei nomi di livello superiore o una costante con lo stesso nome in un altro modulo (ad esempio :: SomeOtherModule :: ClassMethods).
Benjamin Oakes,

2
È molto simile
all'operando

111

Questo semplice esempio lo illustra:

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

Tratto da http://www.tutorialspoint.com/ruby/ruby_operators.htm


questo è ciò che causa l'avvertimento però. C'è un modo per eludere l'avvertimento?
NullVoxPopuli,

3
@NullVoxPopuli Generalmente la modifica delle costanti è una cosa molto negativa, ma se ad esempio si desidera modificare una costante in una gemma mal scritta e non si vuole biforla , si può fare usando .send (: remove_const) al modulo che definisce esso, quindi ridefinendo la costante.
BookOfGreg,

71

::Consente di accedere a una costante, modulo o classe definita all'interno di un'altra classe o modulo. Viene utilizzato per fornire spazi dei nomi in modo che i nomi dei metodi e delle classi non siano in conflitto con altre classi di autori diversi.

Quando vedi ActiveRecord::Basein Rails significa che Rails ha qualcosa di simile

module ActiveRecord
  class Base
  end
end

vale a dire una classe chiamata Baseall'interno di un modulo a ActiveRecordcui viene fatto riferimento come ActiveRecord::Base(è possibile trovarlo nella sorgente Rails in activerecord-nnn / lib / active_record / base.rb)

Un uso comune di :: è quello di accedere alle costanti definite nei moduli ad es

module Math
  PI = 3.141 # ...
end

puts Math::PI

L' ::operatore non consente di ignorare la visibilità dei metodi contrassegnati come privati ​​o protetti.


7
Quindi, se uno ha class MyClass < ActiveRecord::Base, significa che MyClass eredita solo i metodi dalla base di classe e non nulla all'interno del modulo ActiveRecord?
Charlie Parker,

2
Perché usare lo speciale doppio punto per questa risoluzione dello spazio dei nomi piuttosto che usare "." anche per questo? Il contesto e le maiuscole eviterebbero la confusione di significato anche se stessimo usando il ".", No?
Giona

3
@Jonah ci sono alcuni casi in cui sarebbe ambiguo. ad es. considerare class Foo; Baz = 42; def self.Baz; "Baz method!"; end; end(perfettamente valido) Foo::Baz # => 42e Foo.Baz # => "Baz method!". Si noti che Foo::Baz()(tra parentesi) chiamerebbe anche il metodo però.
mikej,

3
Quindi il caso d'uso risolve la possibilità di avere una costante di classe e un metodo di classe con lo stesso identico nome? Questo non sembra un argomento forte a favore della funzionalità. Personalmente preferirei perdere quell'abilità (sembra comunque un problema), perdere il doppio colon e usare "." anche per lo spazio dei nomi .... Forse ci sono altri casi d'uso che risolve?
Giona,

26

A che serve l'ambito (privato, protetto) se puoi semplicemente usare :: per esporre qualcosa?

In Ruby, tutto è esposto e tutto può essere modificato da qualsiasi altra parte.

Se sei preoccupato per il fatto che le classi possono essere cambiate dall'esterno della "definizione di classe", probabilmente Ruby non fa per te.

D'altra parte, se sei frustrato dal blocco delle classi di Java, allora Ruby è probabilmente quello che stai cercando.


1
Ho sentito alcuni rubyists dire che le variabili di istanza non sono esposte, il che attr_accessorrende semplicemente metodi che modificano la variabile. (Poi di nuovo c'è instance_eval)
Andrew Grimm,

4
Esatto, c'è instance_eval. Ma c'è anche instance_variable_gete instance_variable_set. Ruby è troppo dinamico per i vincoli.
yfeldblum,

12

Aggiungendo alle risposte precedenti, è valido Ruby da utilizzare ::per accedere ai metodi di istanza. Sono validi tutti i seguenti:

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

Secondo le migliori pratiche, credo sia raccomandato solo l'ultimo.


11

No, non è per accedere a tutti i metodi, è un operatore di "risoluzione", cioè lo usi per risolvere l'ambito (o la posizione che puoi dire) di un simbolo costante / statico.

Ad esempio nella prima riga, Rails lo usa per trovare la classe Base all'interno di ActiveRecord.Module, nel secondo viene usato per individuare il metodo di classe (statico) della classe Route, ecc. Ecc.

Non è usato per esporre nulla, è usato per "localizzare" cose attorno ai tuoi scopi.

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


per "(statico)" intendi "(disegna)"?!?
Meltemi,

8

Sorprendentemente, tutte e 10 le risposte qui dicono la stessa cosa. '::' è un operatore di risoluzione dello spazio dei nomi, e sì è vero. Ma c'è un gotcha che devi capire sull'operatore di risoluzione dello spazio dei nomi quando si tratta dell'algoritmo di ricerca costante . Come Matz delinea nel suo libro "Il linguaggio di programmazione Ruby", la ricerca costante ha più passaggi. Innanzitutto, cerca una costante nell'ambito lessicale in cui si fa riferimento alla costante. Se non trova la costante nell'ambito lessicale, cerca la gerarchia dell'ereditarietà . A causa di questo algoritmo di ricerca costante, di seguito otteniamo i risultati previsti:

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

Mentre F eredita da E, il modulo B rientra nell'ambito lessicale di F. Di conseguenza, le istanze F faranno riferimento al costante PI definito nel modulo B. Ora se il modulo B non ha definito PI, allora le istanze F si riferiranno al PI costante definita nella superclasse E.

E se dovessimo usare '::' anziché i moduli di nidificazione? Otterremmo lo stesso risultato? No!

Utilizzando l'operatore di risoluzione dello spazio dei nomi durante la definizione dei moduli nidificati, i moduli e le classi nidificati non rientrano più nell'ambito lessicale dei loro moduli esterni. Come puoi vedere di seguito, PI definito in A :: B non rientra nell'ambito lessicale di A :: B :: C :: D e quindi otteniamo una costante non inizializzata quando proviamo a fare riferimento a PI nel metodo dell'istanza get_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

Si tratta di impedire che le definizioni si scontrino con altri codici collegati al progetto. Significa che puoi tenere le cose separate.

Ad esempio, puoi avere un metodo chiamato "run" nel tuo codice e sarai comunque in grado di chiamare il tuo metodo piuttosto che il metodo "run" che è stato definito in qualche altra libreria a cui sei collegato.


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

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

:: Viene utilizzato per creare un ambito. Per accedere a Constant EATER da 2 moduli, è necessario eseguire l'ambito dei moduli per raggiungere la costante


3

Ruby on rails utilizza ::per la risoluzione dello spazio dei nomi.

class User < ActiveRecord::Base

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

end

Per usarlo :

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

Inoltre, l'altro utilizzo è: quando si utilizzano percorsi nidificati

OmniauthCallbacksController è definito sotto gli utenti.

E indirizzato come:

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


class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController

end
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.