รูบีแบบทวิภาค `::` คืออะไร?


427

ลำไส้ใหญ่คู่นี้คือ::อะไร Foo::Barเช่น

ฉันพบคำจำกัดความ :

The ::เป็นตัวดำเนินการเอกที่อนุญาตให้: ค่าคงที่, วิธีการอินสแตนซ์และวิธีการเรียนที่กำหนดไว้ในชั้นเรียนหรือโมดูลที่จะเข้าถึงได้จากทุกที่นอกชั้นเรียนหรือโมดูล

สิ่งที่ดีคือขอบเขต (ส่วนตัวได้รับการป้องกัน) ถ้าคุณสามารถใช้::เพื่อเปิดเผยอะไร


175
เพื่อประโยชน์ของ googler ในอนาคตหากคุณพยายามค้นหาสัญลักษณ์ลองsymbolhound.com
Andrew Grimm

1
เป็นไปได้ซ้ำไหม stackoverflow.com/questions/2276905/what-does-mean-in-ruby
iX3

เช่นเดียวกับstackoverflow.com/questions/3597096/…
1dolinski

6
ให้ศีลคุณ @AndrewGrimm นั่นคือสิ่งที่ดีที่สุดที่ฉันเคยเห็นในสัปดาห์นี้
abeger

คำตอบ:


381

::นั้นเป็นตัวดำเนินการแก้ไขเนมสเปซ ช่วยให้คุณเข้าถึงรายการในโมดูลหรือรายการระดับชั้นในชั้นเรียน ตัวอย่างเช่นสมมติว่าคุณมีการตั้งค่านี้:

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

คุณสามารถเข้าถึงจากภายนอกโมดูลที่เป็นCONSTANTSomeModule::InnerModule::MyClass::CONSTANT

มันไม่ส่งผลกระทบต่อวิธีการอินสแตนซ์ที่กำหนดไว้ในชั้นเรียนเนื่องจากคุณเข้าถึงผู้ที่มีไวยากรณ์ที่แตกต่างกัน (จุด.)

หมายเหตุที่เกี่ยวข้อง: ถ้าคุณต้องการกลับไปที่ namespace ระดับบนสุดให้ทำดังนี้ :: SomeModule - Benjamin Oakes


5
ใน C # เช่นใช่ ในทางกลับกัน C ++ (และ Ruby) ใช้::สำหรับการแก้ไขเนมสเปซเช่นstd::cout << "Hello World!";
Jerry Fernholz

142
หมายเหตุที่เกี่ยวข้อง: หากคุณต้องการกลับไปที่เนมสเปซระดับบนให้ทำดังนี้: ::SomeModule
Benjamin Oakes

5
@Benjamin โคลอนนำจะส่อให้เห็นเว้นแต่ว่าฉันจะมี SomeModule ในโมดูลอื่นและฉันต้องการได้ระดับบนสุดแทนใช่ไหม?
Jo Liss

7
@Jo ใช่ มันจะมีประโยชน์ถ้าคุณต้องการให้แน่ใจว่าคุณอ้างถึงค่าคงที่ที่ namespace ระดับบนสุดหรือค่าคงที่ที่มีชื่อเดียวกันในโมดูลอื่น (เช่น :: SomeOtherModule :: ClassMethods)
Benjamin Oakes

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

3
@NullVoxPopuli โดยทั่วไปการแก้ไขค่าคงที่เป็นสิ่งที่ไม่ดีจริงๆ แต่ถ้าคุณต้องการแก้ไขค่าคงที่ในอัญมณีที่เขียนไม่ดีและไม่ต้องการแยกมันก็สามารถทำได้โดยใช้. ส่ง (: remove_const)กับโมดูลที่กำหนด จากนั้นกำหนดค่าคงที่ใหม่
BookOfGreg

71

::ให้คุณเข้าถึงค่าคงที่โมดูลหรือคลาสที่กำหนดภายในคลาสหรือโมดูลอื่น มันถูกใช้เพื่อระบุเนมสเปซเพื่อให้เมธอดและชื่อคลาสไม่ขัดแย้งกับคลาสอื่น ๆ

เมื่อคุณเห็นActiveRecord::Baseใน Rails หมายความว่า Rails มีลักษณะคล้ายกัน

module ActiveRecord
  class Base
  end
end

เช่นคลาสที่เรียกว่าBaseภายในโมดูลActiveRecordซึ่งอ้างอิงแล้วว่าเป็นActiveRecord::Base(คุณสามารถค้นหาได้ในแหล่ง Rails ใน activerecord-nnn / lib / active_record / base.rb)

การใช้งานทั่วไปของ :: คือการเข้าถึงค่าคงที่ที่กำหนดไว้ในโมดูลเช่น

module Math
  PI = 3.141 # ...
end

puts Math::PI

::ผู้ประกอบการไม่ได้ช่วยให้คุณสามารถมองเห็นบายพาสวิธีการทำเครื่องหมายส่วนตัวหรือการป้องกัน


7
ดังนั้นถ้ามีclass MyClass < ActiveRecord::Baseนั่นหมายความว่า MyClass จะสืบทอดเมธอดจากคลาสพื้นฐานเท่านั้นและไม่ใช่สิ่งใด ๆ ในโมดูล ActiveRecord
Charlie Parker

2
เหตุใดจึงใช้ double-colon พิเศษสำหรับการแก้ไขเนมสเปซนี้แทนที่จะใช้ "." สำหรับสิ่งนี้ด้วย? บริบทและการใช้อักษรตัวพิมพ์ใหญ่จะป้องกันความสับสนของความหมายแม้ว่าเราจะใช้ "." ใช่มั้ย
โยนาห์

3
@ Jonah มีบางกรณีที่มันจะคลุมเครือ เช่นพิจารณา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 ที่ถูกล็อคไว้ทับทิมอาจเป็นสิ่งที่คุณกำลังมองหา


1
ฉันเคยได้ยินนักบวชบางคนบอกว่าตัวแปรอินสแตนซ์นั้นไม่ได้รับการเปิดเผยแม้attr_accessorเพียงแค่สร้างวิธีการที่ปรับเปลี่ยนตัวแปร (จากนั้นอีกครั้งมีinstance_eval)
แอนดรูกริมม์

4
instance_evalที่ถูกต้องมี แต่ยังมีและinstance_variable_get instance_variable_setRuby เป็นแบบไดนามิกเกินไปสำหรับข้อ จำกัด
yfeldblum

12

การเพิ่มคำตอบก่อนหน้านี้เป็นทับทิมที่ถูกต้องเพื่อใช้::ในการเข้าถึงวิธีการอินสแตนซ์ ทั้งหมดต่อไปนี้ถูกต้อง:

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

ตามแนวทางปฏิบัติที่ดีที่สุดฉันเชื่อว่ามีเพียงแนวทางสุดท้ายที่แนะนำ


11

ไม่มันไม่ได้เข้าถึงทุกวิธีมันเป็นตัวดำเนินการ "การแก้ปัญหา" นั่นคือคุณใช้เพื่อแก้ไขขอบเขต (หรือตำแหน่งที่คุณสามารถพูดได้) ของสัญลักษณ์คงที่ / แบบคงที่

ตัวอย่างเช่นในบรรทัดแรกของคุณ Rails ใช้เพื่อค้นหาคลาส Base ภายใน ActiveRecord.Module ในรายการที่สองของคุณจะถูกใช้เพื่อค้นหาเมธอด class (สแตติก) ของคลาส Routes และอื่น ๆ

มันไม่ได้ใช้เพื่อแสดงอะไรมันใช้เพื่อ "ค้นหา" สิ่งรอบ ๆ ขอบเขตของคุณ

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


โดย "(คงที่)" คุณหมายถึง "(วาด)"?!?
Meltemi

8

น่าแปลกใจที่ทั้ง 10 คำตอบที่นี่พูดในสิ่งเดียวกัน '::' เป็นตัวดำเนินการแก้ไขเนมสเปซและใช่เป็นจริง แต่มีหนึ่ง gotcha ที่คุณต้องรู้เกี่ยวกับผู้ประกอบการที่มีความละเอียด namespace เมื่อมันมาถึงขั้นตอนวิธีการค้นหาอย่างต่อเนื่อง เมื่อ Matz แยกตัวในหนังสือของเขา 'The Ruby Programming Language' การค้นหาคงที่มีหลายขั้นตอน ก่อนอื่นมันจะค้นหาค่าคงที่ในขอบเขตของคำซึ่งอ้างอิงค่าคงที่ ถ้ามันไม่ได้หาอย่างต่อเนื่องภายในขอบเขตคำศัพท์มันก็จะค้นหาลำดับชั้นมรดก เนื่องจากอัลกอริทึมการค้นหาแบบคงที่ด้านล่างเราจึงได้ผลลัพธ์ที่ต้องการ:

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 จะอ้างถึงค่าคงที่ PI ที่กำหนดไว้ในโมดูล B ตอนนี้ถ้าโมดูล B ไม่ได้กำหนด PI ดังนั้นอินสแตนซ์ F จะอ้างถึง PI ค่าคงที่ที่กำหนดใน superclass E

แต่ถ้าเราใช้ '::' แทนการซ้อนโมดูลล่ะ เราจะได้ผลเหมือนกันไหม? No!

โดยใช้โอเปอเรเตอร์การแก้ปัญหาเนมสเปซเมื่อกำหนดโมดูลที่ซ้อนกันโมดูลและคลาสที่ซ้อนกันจะไม่อยู่ในขอบเขตศัพท์ของโมดูลภายนอก ดังที่คุณเห็นด้านล่าง PI ที่กำหนดใน A :: B ไม่อยู่ในขอบเขตศัพท์ของ A :: B :: C :: D และทำให้เราได้ค่าคงตัวที่ไม่กำหนดเมื่อพยายามอ้างถึง PI ในเมธอดอินสแตนซ์ 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

มันคือทั้งหมดที่เกี่ยวกับการป้องกันคำจำกัดความจากการปะทะกับรหัสอื่น ๆ ที่เชื่อมโยงกับโครงการของคุณ หมายความว่าคุณสามารถแยกสิ่งต่าง ๆ ออกจากกันได้

ตัวอย่างเช่นคุณสามารถมีวิธีหนึ่งที่เรียกว่า "เรียกใช้" ในรหัสของคุณและคุณจะยังคงสามารถเรียกวิธีการของคุณได้มากกว่าวิธี "เรียกใช้" ที่กำหนดไว้ในห้องสมุดอื่น ๆ ที่คุณเชื่อมโยง


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

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

:: ใช้ในการสร้างขอบเขต ในการเข้าถึง Constant EATER จาก 2 โมดูลเราจำเป็นต้องกำหนดขอบเขตของโมดูลให้สามารถเข้าถึงได้ถึงค่าคงที่


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.