web-dev-qa-db-fra.com

Quel est le double-colon de Ruby `::`?

Quel est ce double-colon ::? Par exemple. Foo::Bar.

J'ai trouvé un définition :

:: est un opérateur unaire qui permet d'accéder aux constantes, méthodes d'instance et méthodes de classe définies dans une classe ou un module à partir de l'extérieur de la classe ou du module.

A quoi bon scope (private, protected) si vous pouvez simplement utiliser :: pour exposer quoi que ce soit?

401
Meltemi

:: est fondamentalement un opérateur de résolution d'espace de noms. Il vous permet d'accéder à des éléments de modules ou à des éléments de niveau de classe. Par exemple, supposons que vous ayez cette configuration:

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

Vous pouvez accéder à CONSTANT de l'extérieur du module en tant que SomeModule::InnerModule::MyClass::CONSTANT.

Cela n'affecte pas les méthodes d'instance définies sur une classe, puisque vous accédez à celles avec une syntaxe différente (le point .).

Remarque pertinente: Si vous souhaitez revenir à l'espace de noms de niveau supérieur, procédez comme suit: :: SomeModule - Benjamin Oakes

357
mipadi

Cet exemple simple l'illustre:

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
puts Foo::MR_COUNT  # this is the local "Foo" constant

Tiré de http://www.tutorialspoint.com/Ruby/ruby_operators.htm

107
Nader

:: Vous permet d'accéder à une constante, à un module ou à une classe définie dans une autre classe ou un autre module. Il est utilisé pour fournir des espaces de noms afin que les noms de méthodes et de classes n'entrent pas en conflit avec d'autres classes d'auteurs différents.

Lorsque vous voyez ActiveRecord::Base dans Rails, cela signifie que Rails a quelque chose comme:

module ActiveRecord
  class Base
  end
end

c'est-à-dire une classe appelée Base à l'intérieur d'un module ActiveRecord qui est ensuite référencé comme ActiveRecord::Base (vous pouvez le trouver dans la source Rails dans activerecord-nnn/lib/active_record /base.rb)

Une utilisation courante de :: est d’accéder aux constantes définies dans les modules, par exemple.

module Math
  PI = 3.141 # ...
end

puts Math::PI

L'opérateur :: ne vous permet pas de contourner la visibilité des méthodes marquées comme privées ou protégées.

70
mikej

À quoi sert scope (privé, protégé) si vous pouvez simplement utiliser :: pour exposer quoi que ce soit?

En Ruby, tout est exposé et tout peut être modifié de n'importe où.

Si vous êtes préoccupé par le fait que les classes peuvent être modifiées en dehors de la "définition de classe", alors Ruby ne vous convient probablement pas.

D'un autre côté, si vous êtes frustré par le verrouillage des classes de Java, alors Ruby est probablement ce que vous recherchez.

23
yfeldblum

Non, il ne s'agit pas d'accéder à toutes les méthodes, il s'agit d'un opérateur "résolution", c'est-à-dire que vous l'utilisez pour résoudre la portée (ou l'emplacement que vous pouvez dire) d'un symbole constant/statique.

Par exemple, dans le premier de votre ligne, Rails l'utilise pour rechercher la classe Base à l'intérieur d'ActiveRecord.Module, dans le second, il est utilisé pour localiser la méthode de classe (statique) de la classe Routes, etc. , etc.

Il n'est pas utilisé pour exposer quoi que ce soit, il est utilisé pour "localiser" des choses autour de votre portée.

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

11
Francisco Soto

En ajoutant aux réponses précédentes, il est valide Ruby d'utiliser :: pour accéder aux méthodes d'instance. Tous les éléments suivants sont valables:

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

Selon les meilleures pratiques, je crois que seul le dernier est recommandé.

8
Yuri Ghensev

Il s’agit d’empêcher que les définitions ne se heurtent à d’autres codes liés à votre projet. Cela signifie que vous pouvez garder les choses séparées.

Par exemple, vous pouvez avoir une méthode appelée "run" dans votre code et vous pourrez toujours appeler votre méthode plutôt que la méthode "run" définie dans une autre bibliothèque que vous avez liée.

4
Mongus Pong

Étonnamment, les 10 réponses ici disent la même chose. Le '::' est un opérateur de résolution d'espace de noms, et c'est vrai. Mais il faut comprendre l’opérateur de résolution d’espace de nommage algorithme de recherche constante. Comme Matz le décrit dans son livre, 'Le langage de programmation Ruby _', la recherche constante comporte plusieurs étapes. Premièrement, il recherche une constante dans le portée lexicale où la constante est référencée. S'il ne trouve pas la constante dans la portée lexicale, il recherche alors hiérarchie d'héritage. En raison de cet algorithme de recherche constante, nous obtenons ci-dessous les résultats attendus:

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

Tandis que F hérite de E, le module B est dans la portée lexicale de F. Par conséquent, les instances F feront référence à la constante PI définie dans le module B. Maintenant, si le module B n'a pas défini PI, les instances F font référence à PI constante définie dans la superclasse E.

Mais que se passerait-il si nous utilisions '::' plutôt que des modules d'imbrication? Aurions-nous le même résultat? Non!

En utilisant l'opérateur de résolution d'espace de noms lors de la définition de modules imbriqués, les modules et les classes imbriquées ne font plus partie de la portée lexicale de leurs modules externes. Comme vous pouvez le voir ci-dessous, PI défini dans A :: B n'est pas dans la portée lexicale de A :: B :: C :: D et nous obtenons donc une constante non initialisée lorsque nous essayons de faire référence à PI dans la méthode d'instance 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
3
Donato

Ruby on Rails utilise :: pour la résolution de l'espace de noms.

class User < ActiveRecord::Base

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

end

Pour l'utiliser :

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

En outre, une autre utilisation est: lors de l'utilisation d'itinéraires imbriqués

OmniauthCallbacksController est défini sous utilisateurs.

et la route est comme:

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


class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController

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

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

:: Est utilisé pour créer une portée. Pour accéder à Constant EATER à partir de 2 modules, nous devons définir la portée des modules afin d’atteindre la

2