ตัวแปรอินสแตนซ์: self vs @


179

นี่คือรหัสบางส่วน:

class Person
  def initialize(age)
    @age = age
  end

  def age
    @age
  end

  def age_difference_with(other_person)
    (self.age - other_person.age).abs
  end

  protected :age
end

สิ่งที่ฉันต้องการที่จะทราบความแตกต่างระหว่างการใช้@ageและself.ageในage_difference_withวิธีการ

คำตอบ:


260

การเขียน@ageเข้าถึงตัวแปรอินสแตนซ์@ageโดยตรง เขียนself.ageบอกวัตถุที่จะส่งข้อความตัวเองageซึ่งมักจะกลับตัวแปรเช่น@age- แต่จะทำจำนวนของสิ่งอื่น ๆ ขึ้นอยู่กับวิธีการageวิธีการจะดำเนินการในประเภทรองให้ ตัวอย่างเช่นคุณอาจมีคลาส MiddleAgedSocialite ที่รายงานอายุ 10 ปีที่อายุน้อยกว่าที่เป็นจริง หรือในทางปฏิบัติคลาส PersistentPerson อาจอ่านข้อมูลจากที่จัดเก็บแบบถาวรอย่างเกียจคร้านแคชข้อมูลถาวรทั้งหมดในแฮช


2
ฉันเคยอ่านหนังสือในรถไฟและไม่เข้าใจความแตกต่างระหว่างตัวเองกับ @ ดังนั้นฉันควรใช้ self.var_name ในวิธีการของฉัน (ที่ไม่ได้ตั้งค่าและทะเยอทะยาน) เพื่อให้ข้อมูลของฉันโดยใช้ส่วนต่อประสานสาธารณะฉัน ใช้เวลาในการกำหนดมันในทะเยอทะยานและ Setter ใช่ไหม?
sarunw

1
... english ... คุณหมายถึงอะไรหลาย ๆ อย่าง ฉันไม่ได้รับสองตัวอย่างสุดท้ายที่ให้มา
user2167582

23

ความแตกต่างคือมันแยกการใช้วิธีการจากการใช้งานของมัน หากการดำเนินการของทรัพย์สินมีการเปลี่ยนแปลง - พูดเพื่อเก็บวันเกิดแล้วคำนวณอายุตามความแตกต่างของเวลาระหว่างวันนี้และวันเกิด - รหัสนั้นขึ้นอยู่กับวิธีการที่ไม่จำเป็นต้องเปลี่ยน หากใช้คุณสมบัติโดยตรงการเปลี่ยนแปลงจะต้องเผยแพร่ไปยังส่วนอื่น ๆ ของรหัส ในแง่นี้การใช้คุณสมบัติโดยตรงนั้นบอบบางกว่าการใช้อินเทอร์เฟซที่จัดหาให้ในคลาส


15
โอ้เพราะ self.age สามารถอ้างถึงตัวแปรอินสแตนซ์หรือวิธีการอินสแตนซ์?
โนแลนเอมี

@. @ ... เศร้านี่เป็นกรณี
cyc115

7

ถูกเตือนเมื่อคุณรับคลาสStruct.newซึ่งเป็นวิธีที่เรียบร้อยในการสร้าง intializer ( วิธีสร้าง initializer ใน Ruby? )

class Node < Struct.new(:value)
    def initialize(value)
        @value = value
    end
    def show()
        p @value
        p self.value # or `p value`
    end
end 

n = Node.new(30)
n.show()

จะกลับมา

30
nil

อย่างไรก็ตามเมื่อคุณลบ initializer มันจะกลับมา

nil
30

ด้วยคำจำกัดความของคลาส

class Node2
    attr_accessor :value
    def initialize(value)
        @value = value
    end
    def show()
        p @value
        p self.value
    end
end

คุณควรจัดทำคอนสตรัคเตอร์

n2 = Node2.new(30)
n2.show()

จะกลับมา

30
30

ขอบคุณสำหรับตัวอย่าง @Prosseek ฉันกำลังเรียนรู้ Ruby on Rails และนี่เป็นพฤติกรรมที่ทำให้ฉันรู้สึกว่า Ruby มีความซับซ้อนโดยไม่จำเป็น>.
cyc115

3

คำตอบแรกนั้นถูกต้องทั้งหมด แต่ในฐานะที่เป็นมือใหม่ที่สัมพันธ์กันมันไม่ชัดเจนสำหรับฉันเลยในสิ่งที่มันบอกเป็นนัย (ส่งข้อความถึงตัวเอง? uh huh ... ) ฉันคิดว่าตัวอย่างสั้น ๆ จะช่วย:

class CrazyAccessors
  def bar=(val)
    @bar = val - 20 # sets @bar to (input - 20)
  end
  def bar
    @bar
  end

  def baz=(value)
    self.bar = value # goes through `bar=` method, so @bar = (50 - 20)
  end

  def quux=(value)
    @bar = value     # sets @bar directly to 50
  end
end

obj  = CrazyAccessors.new
obj.baz = 50
obj.bar  # => 30
obj.quux = 50
obj.bar  # => 50

8
ตัวอย่างนี้ทำให้สิ่งต่าง ๆ สับสนมากขึ้น
Oskar Holmkratz

1
ฉันขอโทษ แต่ตัวอย่างไม่ได้มีความคิดเห็นเพียงพอสำหรับฉัน ฉันไม่สามารถทำตามเหตุผลของคุณ
kouty

คนที่มาจากสมอลทอล์คจะพูดว่าวัตถุ "ส่งข้อความถึงตัวเอง" คนที่มาจาก Python จะบอกว่าวัตถุ "เรียกวิธีการในตัวเอง" อย่าสับสน พวกเขาเป็นสิ่งเดียวกัน (ความหมายพิถีพิถันอาจคัดค้านว่าพวกเขาเป็นเพียงคนเดียวสำหรับภาษาที่มีการพิมพ์แบบไดนามิกและการเรียกวิธีการเสมือน C ++ ไม่เหมือนกับการส่งข้อความตรงไปตรงมาคนพิถีพิถันถูกต้อง แต่อาจเกินขอบเขตของคำถามนี้ / คำตอบ)
GrandOpener

ฉันชอบตัวอย่าง แต่โปรดให้ความคิดเห็นเพิ่มเติมเกี่ยวกับสิ่งที่เกิดขึ้นจริง ยากที่จะติดตามโดยไม่มีคำอธิบาย
CalamityAdam

2

ไม่มีความแตกต่าง ฉันสงสัยว่ามันทำเพื่อคุณค่าทางสารคดีในการมองเห็นself.ageและother_person.ageใกล้กัน

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

แต่นั่นเป็นสิ่งที่เป็นนามธรรมที่ไม่น่าเป็นไปได้ที่จะต้องกังวลหลังจากทั้งหมดหากการใช้งานวัตถุเปลี่ยนแปลงไปมันมีเหตุผลที่จะเปลี่ยนวิธีการอื่น ๆ ในบางจุดการอ้างอิงอย่างง่าย ๆ ภายในตัววัตถุเองนั้นสมเหตุสมผลอย่างสมบูรณ์

ไม่ว่าในกรณีใดนามธรรมของageคุณสมบัติยังคงไม่ได้อธิบายการใช้อย่างชัดเจนselfเนื่องจากเพียงแค่ธรรมดาageก็จะเรียกใช้ accessor


-3

@age - แน่นอนอายุตัวแปรอินสแตนซ์

self.age - หมายถึงอายุคุณสมบัติอินสแตนซ์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.