Variabel Instance: self vs @

179

Ini beberapa kode:

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

Apa yang saya ingin tahu adalah perbedaan antara menggunakan @agedan self.agedi age_difference_withmetode.

sarunw
sumber

Jawaban:

260

Menulis @agesecara langsung mengakses variabel instan @age. Menulis self.agememberitahu objek untuk mengirim sendiri pesannya age, yang biasanya akan mengembalikan variabel instan @age- tetapi bisa melakukan sejumlah hal lain tergantung pada bagaimana agemetode ini diterapkan dalam subkelas yang diberikan. Misalnya, Anda mungkin memiliki kelas MiddleAgedSocialite yang selalu melaporkan usianya 10 tahun lebih muda daripada yang sebenarnya. Atau lebih praktisnya, kelas PersistentPerson mungkin malas membaca data itu dari toko persistent, cache semua data persistennya dalam sebuah hash.

Membuang
sumber
2
Saya pernah membaca buku di rails dan tidak mengerti perbedaan antara self ini dan @, jadi saya harus selalu menggunakan self.var_name dalam metode saya (yang tidak setter dan pengambil) untuk membuat data saya menggunakan antarmuka publik, saya menghabiskan waktu mendefinisikannya dalam pengambil dan penyetel, bukan?
sarunw
1
... bahasa Inggris ... apa yang Anda maksud dengan sejumlah hal. saya tidak mendapatkan dua contoh terakhir yang diberikan.
user2167582
23

Perbedaannya adalah bahwa ia mengisolasi penggunaan metode dari implementasi itu. Jika implementasi properti diubah - katakan untuk menjaga tanggal lahir dan kemudian hitung usia berdasarkan perbedaan waktu antara sekarang dan tanggal lahir - maka kode tergantung pada metode tidak perlu diubah. Jika menggunakan properti secara langsung, maka perubahan perlu disebarkan ke area kode yang lain. Dalam hal ini, menggunakan properti secara langsung lebih rapuh daripada menggunakan antarmuka kelas yang disediakan untuk itu.

tvanfosson
sumber
15
Ohhh, karena self.age bisa merujuk ke variabel instan atau metode instance?
Nolan Amy
@. @ ... sedih ini masalahnya
cyc115
7

Berhati-hatilah ketika Anda mewarisi kelas Struct.newyang merupakan cara yang rapi untuk menghasilkan intializer ( Bagaimana cara menghasilkan initializer di 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()

akan kembali

30
nil

Namun, ketika Anda menghapus initializer, itu akan kembali

nil
30

Dengan definisi kelas

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

Anda harus menyediakan konstruktor.

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

akan kembali

30
30
prosseek
sumber
Terima kasih untuk contoh @Prosseek, saya saat ini belajar Ruby on Rails dan ini adalah persis perilaku yang membuat saya merasa Ruby tidak perlu rumit>. <.
cyc115
3

Jawaban pertama sepenuhnya benar, tetapi sebagai pemula relatif tidak segera jelas bagi saya apa yang tersirat (mengirim pesan ke diri sendiri? Eh ya ...). Saya pikir contoh singkat akan membantu:

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
gumpal
sumber
8
Contoh ini membuat segalanya lebih membingungkan.
Oskar Holmkratz
1
Saya minta maaf tapi contohnya tidak cukup banyak komentar untuk saya. Saya tidak bisa mengikuti alasan Anda.
kouty
Seseorang yang datang dari Smalltalk akan mengatakan bahwa suatu objek "mengirim pesan ke dirinya sendiri." Seseorang yang datang dari Python akan mengatakan bahwa objek "memanggil metode itu sendiri." Jangan bingung; mereka persis sama. (Purist semantik mungkin berkeberatan bahwa mereka hanya sama untuk bahasa dengan pengetikan dinamis dan bahwa panggilan metode virtual C ++ tidak persis sama dengan mengirim pesan. Purist benar, tapi itu mungkin di luar cakupan pertanyaan ini / jawaban.)
GrandOpener
Saya suka contohnya, tapi tolong berikan komentar lagi tentang apa yang sebenarnya terjadi. Sulit untuk diikuti tanpa penjelasan
CalamityAdam
2

Tidak ada perbedaan. Saya menduga itu dilakukan hanya untuk nilai dokumenter melihat self.agedan other_person.ageberdekatan.

Saya kira penggunaan itu memungkinkan pengambil aktual untuk ditulis di masa depan, yang mungkin melakukan sesuatu yang lebih kompleks daripada hanya mengembalikan variabel instan, dan dalam hal ini metode tersebut tidak perlu diubah.

Tapi itu abstraksi yang tidak perlu dikhawatirkan, jika implementasi objek berubah, masuk akal untuk mengubah metode lain, pada beberapa titik referensi sederhana di dalam objek itu sendiri sangat masuk akal.

Dalam kasus apa pun, abstraksi ageproperti masih tidak menjelaskan penggunaan eksplisit self, karena hanya polos agejuga akan memanggil pengakses.

DigitalRoss
sumber
-3

@age - jelas merupakan usia variabel instan

self.age - mengacu pada usia properti instan.

LEMUEL ADANE
sumber