attr_accessor ใน Ruby คืออะไร


1023

ฉันมีช่วงเวลาที่ยากในการทำความเข้าใจattr_accessorในทับทิม
มีคนอธิบายเรื่องนี้กับฉันได้ไหม



1
attr_accessor ทำงานในลักษณะเดียวกันใน Git หรือไม่ ฉันพบว่าบทช่วยสอนบางคำอธิบายไม่เพียงพอและคนอื่น ๆ คาดเดาความรู้ก่อนหน้านี้
Angelfirenze

10
@Angelfirenze, มีอะไรจะทำอย่างไรกับgit attr_accessorGit เป็นซอฟต์แวร์การควบคุมเวอร์ชันในขณะที่attr_accessorเป็นวิธีการในรูบี
Uzbekjon

คำตอบ:


2359

Personสมมติว่าคุณได้เรียน

class Person
end

person = Person.new
person.name # => no method error

nameเห็นได้ชัดว่าวิธีการที่เราไม่เคยกำหนดไว้ มาทำกันเถอะ

class Person
  def name
    @name # simply returning an instance variable @name
  end
end

person = Person.new
person.name # => nil
person.name = "Dennis" # => no method error

อ่าเราสามารถอ่านชื่อได้ แต่นั่นไม่ได้หมายความว่าเราสามารถกำหนดชื่อได้ นั่นเป็นสองวิธีที่ต่างกัน อดีตที่เรียกว่าอ่านและหลังถูกเรียกว่านักเขียน เรายังไม่ได้สร้างนักเขียนเลยลองทำดู

class Person
  def name
    @name
  end

  def name=(str)
    @name = str
  end
end

person = Person.new
person.name = 'Dennis'
person.name # => "Dennis"

น่ากลัว ตอนนี้เราสามารถเขียนและอ่านตัวแปรอินสแตนซ์@nameโดยใช้วิธีอ่านและนักเขียน ยกเว้นวิธีนี้ทำบ่อยครั้งทำไมต้องเสียเวลาเขียนวิธีการเหล่านี้ทุกครั้ง เราสามารถทำได้ง่ายขึ้น

class Person
  attr_reader :name
  attr_writer :name
end

แม้สิ่งนี้จะได้รับซ้ำ ๆ เมื่อคุณต้องการทั้งผู้อ่านและนักเขียนเพียงแค่ใช้ accessor!

class Person
  attr_accessor :name
end

person = Person.new
person.name = "Dennis"
person.name # => "Dennis"

ทำงานในลักษณะเดียวกัน! และเดาอะไร: ตัวแปรอินสแตนซ์@nameในวัตถุบุคคลของเราจะถูกตั้งค่าเช่นเดียวกับเมื่อเราทำด้วยตนเองดังนั้นคุณสามารถใช้มันในวิธีอื่นได้

class Person
  attr_accessor :name

  def greeting
    "Hello #{@name}"
  end
end

person = Person.new
person.name = "Dennis"
person.greeting # => "Hello Dennis"

แค่นั้นแหละ. เพื่อให้เข้าใจถึงวิธีการattr_reader, attr_writerและattr_accessorวิธีการสร้างจริงวิธีการที่คุณอ่านคำตอบอื่น ๆ , หนังสือ, เอกสารทับทิม


46
@hakunin - ขอบคุณสำหรับคำตอบที่ชัดเจน สิ่งที่ขาดหายไปสำหรับฉันคือสาเหตุที่ไวยากรณ์ของ Ruby แนะนำให้ใช้เครื่องหมาย ':' สำหรับตัวแปรอินสแตนซ์ในคำสั่ง attr_ * ดูเหมือนว่ามันจะตรงไปตรงกว่าที่จะใช้ไวยากรณ์ '@' เดียวกันกับที่ใช้ที่อื่นในชั้นเรียนเพื่ออ้างถึงตัวแปร
จะ

207
@WilliamSmith เพื่อตอบคำถามของคุณคุณต้องเข้าใจว่าattr_accessorเป็นวิธีการที่เรียกว่าในชั้นเรียนปัจจุบันและ:nameเป็นพารามิเตอร์ที่คุณส่งผ่านไปยังวิธีการที่ มันไม่ได้เป็นรูปแบบพิเศษมันเป็นวิธีการที่ง่าย ถ้าคุณจะให้มัน@nameตัวแปรมันจะไม่ทำให้รู้สึกเพราะ @name nilจะมี attr_accessor nilดังนั้นมันจะเป็นเช่นการเขียน คุณไม่ได้ผ่านตัวแปรที่จำเป็นในการสร้างคุณกำลังผ่านชื่อที่คุณต้องการให้ตัวแปรถูกเรียกใช้
Max Chernyak

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

52
ใช้ Rails เป็นเวลา 3 ปีไม่เคยรู้เรื่องนี้เลย Shame
Sean Xiao

5
@Buminda ใช่ แต่เมธอดnameและตัวแปร@nameไม่เหมือนกัน อย่าสับสนพวกเขา คุณมีตัวแปรอินสแตนซ์@nameในชั้นเรียนของคุณและคุณกำหนดattr_reader :nameให้สามารถอ่านได้จากภายนอก หากattr_readerไม่มีวิธีง่ายๆคุณสามารถเข้าถึง@nameนอกห้องเรียนได้
Max Chernyak

127

attr_accessorเป็นเพียงวิธีการหนึ่ง (ลิงก์ควรให้ข้อมูลเชิงลึกมากขึ้นเกี่ยวกับวิธีการทำงาน - ดูที่วิธีการสร้างคู่และการสอนควรแสดงวิธีการใช้งาน)

เคล็ดลับคือว่าclassเป็นไม่ได้เป็นความหมายในรูบี (มันเป็น "เพียงแค่คำนิยาม" ในภาษาเช่น C ++ และ Java) แต่มันเป็นการแสดงออกที่ประเมิน มันเป็นในระหว่างการประเมินผลนี้เมื่อattr_accessorวิธีการที่ถูกเรียกซึ่งในทางกลับกันแก้ไขชั้นปัจจุบัน - จำผู้รับโดยปริยาย: self.attr_accessorซึ่งselfเป็นวัตถุระดับ "เปิด" ที่จุดนี้

ความต้องการattr_accessorและเพื่อนคือ:

  1. Ruby เช่น Smalltalk ไม่อนุญาตให้เข้าถึงตัวแปรอินสแตนซ์นอกเมธอด 1สำหรับวัตถุนั้น นั่นคือตัวแปรอินสแตนซ์ไม่สามารถเข้าถึงได้ในx.yรูปแบบตามปกติในการพูด Java หรือแม้กระทั่งงูหลาม ในทับทิมyจะถูกนำมาใช้เป็นข้อความที่จะส่ง (หรือ "วิธีการโทร") ดังนั้นattr_*เมธอดจะสร้าง wrappers ที่พร็อกซี@variableเข้าถึงอินสแตนซ์ผ่านวิธีที่สร้างขึ้นแบบไดนามิก

  2. หม้อไอน้ำครับ

หวังว่านี่จะอธิบายรายละเอียดเล็กน้อยบางอย่าง การเข้ารหัสที่มีความสุข


1สิ่งนี้ไม่เป็นความจริงอย่างเคร่งครัดและมี"เทคนิค" รอบ ๆ สิ่งนี้แต่ไม่มีการสนับสนุนทางไวยากรณ์สำหรับการเข้าถึง "ตัวแปรอินสแตนซ์สาธารณะ"


เมื่อคุณบอกว่า attr_accessor เป็น "เพียงวิธี" ฉันได้รับมัน แต่ไวยากรณ์ที่ใช้เรียกวิธีนั้นเรียกว่าอะไร? ฉันมีปัญหาในการค้นหาส่วนในเอกสารทับทิมที่พูดเกี่ยวกับไวยากรณ์เช่น some_method: name => "อะไรก็ตาม",: notherName,: ฯลฯ
BT

68

attr_accessorคือ (ตามที่ระบุไว้ @pst) เป็นเพียงวิธีการหนึ่ง สิ่งนี้คือการสร้างวิธีการเพิ่มเติมสำหรับคุณ

ดังนั้นรหัสนี้ที่นี่:

class Foo
  attr_accessor :bar
end

เทียบเท่ากับรหัสนี้:

class Foo
  def bar
    @bar
  end
  def bar=( new_value )
    @bar = new_value
  end
end

คุณสามารถเขียนวิธีการนี้ด้วยตัวคุณเองใน Ruby:

class Module
  def var( method_name )
    inst_variable_name = "@#{method_name}".to_sym
    define_method method_name do
      instance_variable_get inst_variable_name
    end
    define_method "#{method_name}=" do |new_value|
      instance_variable_set inst_variable_name, new_value
    end
  end
end

class Foo
  var :bar
end

f = Foo.new
p f.bar     #=> nil
f.bar = 42
p f.bar     #=> 42

3
นี่เป็นตัวอย่างที่ดีของการใช้ metaprogramming ในสถานการณ์ระดับเริ่มต้นที่สุด ดีมาก.
John Simon

2
ฉันกำลังมองหาร่างการนำไปปฏิบัติattr_accessorและพบได้ที่นี่ในที่สุด! แม้ว่ามันจะแก้ปัญหาของฉันได้ แต่ฉันอยากรู้ว่าฉันสามารถหาตัวอย่างการใช้งานเช่นนี้ได้ที่ไหน
Wasif Hossain

40

attr_accessor ง่ายมาก:

attr_accessor :foo

เป็นทางลัดสำหรับ:

def foo=(val)
  @foo = val
end

def foo
  @foo
end

มันไม่มีอะไรมากไปกว่า getter / setter สำหรับวัตถุ


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

25

โดยพื้นฐานแล้วพวกเขาปลอมแอตทริบิวต์ข้อมูลที่สาธารณชนเข้าถึงได้ซึ่ง Ruby ไม่มี


4
แม้ว่าความคิดเห็นนี้จะไม่เป็นประโยชน์ แต่ก็เป็นจริง ไฮไลต์ข้อเท็จจริงที่ว่าแอตทริบิวต์ข้อมูลสาธารณะไม่มีอยู่นอกเมธอด "รับ" ใน Ruby ซึ่งเป็นข้อมูลที่มีประโยชน์จริง ๆ สำหรับคนที่พยายามเรียนรู้ภาษา
Eric Dand

3
สิ่งนี้ไม่ควรถูกลดระดับลง ในฐานะที่เป็นคนที่ไม่ได้เป็นทับทิมพยายามหาสิ่งนี้คำตอบนี้มีประโยชน์มาก!
แบรด

1
เห็นด้วยดูเหมือนจะคล้ายกันมากกับชื่อของ C # {รับ; set;}
David Miler

17

มันเป็นเพียงวิธีการที่กำหนดวิธี getter และ setter สำหรับตัวแปรอินสแตนซ์ ตัวอย่างการใช้งานจะเป็น:

def self.attr_accessor(*names)
  names.each do |name|
    define_method(name) {instance_variable_get("@#{name}")} # This is the getter
    define_method("#{name}=") {|arg| instance_variable_set("@#{name}", arg)} # This is the setter
  end
end

การจัดการคุณสมบัติหลายอย่างด้วยวิธีนี้ยอดเยี่ยม!
Wasif Hossain

นี่เป็นข้อมูลโค้ดที่มีประโยชน์จริงๆในการแก้ไขคำถามอื่นที่ฉันเกี่ยวข้องกับ metaprogramming
alexventuraio

15

คำอธิบายง่ายๆโดยไม่มีรหัสใด ๆ

คำตอบข้างต้นส่วนใหญ่ใช้รหัส คำอธิบายนี้พยายามที่จะตอบคำถามโดยไม่ใช้คำใด ๆ ผ่านการเปรียบเทียบ / เรื่อง:

บุคคลภายนอกไม่สามารถเข้าถึงความลับของ CIA ภายในได้

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

  • หากคุณอยู่นอก CIA คุณจะสามารถเข้าถึงข้อมูลที่เปิดเผยต่อสาธารณะเท่านั้น หรือเพื่อใช้สำนวน CIA คุณสามารถเข้าถึงข้อมูลที่ "เคลียร์" เท่านั้น

  • ข้อมูลที่ CIA ต้องการเปิดเผยต่อสาธารณชนทั่วไปภายนอก CIA นั้นเรียกว่า: attribute

ความหมายของคุณสมบัติการอ่านและเขียน:

  • ในกรณีของ CIA คุณลักษณะส่วนใหญ่คือ "อ่านอย่างเดียว" ซึ่งหมายความว่าหากคุณเป็นบุคคลภายนอกของ CIA คุณสามารถถาม: "ใครเป็นผู้อำนวยการของ CIA" และคุณจะได้รับคำตอบที่ตรง แต่สิ่งที่คุณไม่สามารถทำได้ด้วยคุณลักษณะ "อ่านอย่างเดียว" คือการเปลี่ยนแปลงการเปลี่ยนแปลงใน CIA เช่นคุณไม่สามารถโทรออกได้และตัดสินใจทันทีว่าคุณต้องการให้ Kim Kardashian เป็นผู้อำนวยการหรือคุณต้องการให้ Paris Hilton เป็นผู้บัญชาการทหารสูงสุด

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

    ในคำอื่น ๆ accessors ช่วยให้คุณสามารถสอบถามหรือทำการเปลี่ยนแปลงกับองค์กรที่ไม่อนุญาตให้บุคคลภายนอกในขึ้นอยู่กับว่า accessors เป็นอ่านหรือเขียน accessors

วัตถุภายในคลาสสามารถเข้าถึงซึ่งกันและกันได้อย่างง่ายดาย

  • ในทางกลับกันถ้าคุณอยู่ในซีไอเอแล้วคุณสามารถเรียกหน่วยปฏิบัติการซีไอเอของคุณในคาบูลได้อย่างง่ายดายเพราะข้อมูลนี้สามารถเข้าถึงได้ง่ายเพราะคุณอยู่ภายในแล้ว แต่ถ้าคุณอยู่นอกซีไอเอคุณจะไม่ได้รับอนุญาตให้เข้าถึง: คุณจะไม่สามารถรู้ได้ว่าพวกเขาคือใคร (อ่านได้) และคุณจะไม่สามารถเปลี่ยนภารกิจได้

สิ่งเดียวกันกับคลาสและความสามารถของคุณในการเข้าถึงตัวแปรคุณสมบัติและวิธีการต่างๆ HTH! คำถามใด ๆ โปรดถามและฉันหวังว่าฉันสามารถชี้แจง


คำอธิบายของคุณสมเหตุสมผลแล้ว! +1 ขออภัยคุณแน่ใจหรือไม่ว่านิพจน์ "ข้อมูลที่ CIA ได้รับการล้างถูกต้องหรือไม่
kouty

มี "เคลียร์" ระดับต่าง ๆ ใน CIA: เช่นลับสุดยอด (ไม่มีใครนอกจากพรีซ) หรือความไว้วางใจสาธารณะ (ทุกคนสามารถอ่านข้อมูลได้) ซีไอเอให้ข้อเท็จจริงที่ยอดเยี่ยมมากมาย!
BKSpurgeon

คุณสมควรได้รับการโหวตสำหรับตัวอย่างของ Kardashian, Paris Hilton :) ฉันคิดว่ามันไม่ดีพอกับทรัมป์สำหรับประธานาธิบดีลองจินตนาการถึงสองคนที่รับผิดชอบ!
rmcsharry

ใช่ นั่นคือสิ่งที่เราต้องการ StackOverflow โดยไม่ต้องใช้รหัส! :-)
Marvin

13

หากคุณคุ้นเคยกับแนวคิด OOP คุณต้องคุ้นเคยกับวิธี getter และ setter attr_accessor ทำเช่นเดียวกันใน Ruby

ทะเยอทะยานและ Setter ด้วยวิธีทั่วไป

class Person
  def name
    @name
  end

  def name=(str)
    @name = str
  end
end

person = Person.new
person.name = 'Eshaan'
person.name # => "Eshaan"

วิธีการตั้งค่า

def name=(val)
  @name = val
end

วิธีการทะเยอทะยาน

def name
  @name
end

วิธี Getter และ Setter ใน Ruby

class Person
  attr_accessor :name
end

person = Person.new
person.name = "Eshaan"
person.name # => "Eshaan"

2
คำอธิบายที่สมบูรณ์แบบ! มันเป็นพฤติกรรมที่มีประโยชน์มากและสามารถถูกแทนที่ได้ง่ายเกินไป
Rubyrider

12

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

เริ่มต้นวิธีการ

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

class Person

  def initialize(name)
    @name = name
  end


  def greeting
    "Hello #{@name}"
  end
end

person = Person.new("Denis")
puts person.greeting

ในรหัสข้างต้นเรากำลังตั้งค่าชื่อ“ เดนิส” โดยใช้วิธีการเตรียมใช้งานโดยส่งเดนนิสผ่านพารามิเตอร์ในการเตรียมใช้งาน หากเราต้องการตั้งชื่อโดยไม่มีวิธีการเริ่มต้นเราสามารถทำเช่นนี้:

class Person
  attr_accessor :name

  # def initialize(name)
  #     @name = name
  # end

  def greeting
    "Hello #{name}"
  end
end

person = Person.new
person.name = "Dennis"
puts person.greeting

ในโค้ดข้างต้นเราตั้งชื่อโดยเรียกใช้เมธอด attr_accessor setter โดยใช้ person.name แทนที่จะตั้งค่าเมื่อเริ่มต้นวัตถุ

ทั้ง "วิธีการ" ในการทำงานนี้ แต่การเริ่มต้นช่วยเราประหยัดเวลาและบรรทัดของรหัส

นี่เป็นงานเริ่มต้นเท่านั้น คุณไม่สามารถเริ่มต้นเป็นวิธีการได้ ในการรับค่าของออบเจกต์อินสแตนซ์คุณจำเป็นต้องใช้ getters และ setters (attr_reader (get), attr_writer (set) และ attr_accessor (ทั้งคู่) ดูด้านล่างสำหรับรายละเอียดเพิ่มเติมเกี่ยวกับสิ่งเหล่านั้น

Getters, Setters (attr_reader, attr_writer, attr_accessor)

Getters, attr_reader: จุดประสงค์ทั้งหมดของผู้เรียกคือส่งคืนค่าของตัวแปรอินสแตนซ์เฉพาะ เยี่ยมชมตัวอย่างโค้ดด้านล่างเพื่อดูรายละเอียดเกี่ยวกับสิ่งนี้

class Item

  def initialize(item_name, quantity)
    @item_name = item_name
    @quantity = quantity
  end

  def item_name
    @item_name
  end

  def quantity
     @quantity
  end
end

example = Item.new("TV",2)
puts example.item_name
puts example.quantity

ในรหัสข้างต้นคุณกำลังเรียกวิธีการ“ item_name” และ“ ปริมาณ” ในตัวอย่างของรายการ“ ตัวอย่าง” “ ใส่ example.item_name” และ“ example.quantity” จะส่งกลับ (หรือ“ รับ”) ค่าสำหรับพารามิเตอร์ที่ส่งผ่านไปยัง“ ตัวอย่าง” และแสดงไปที่หน้าจอ

โชคดีที่ Ruby มีวิธีการที่ทำให้เราสามารถเขียนโค้ดนี้ได้อย่างกระชับยิ่งขึ้น วิธีการ attr_reader ดูรหัสด้านล่าง;

class Item

attr_reader :item_name, :quantity

  def initialize(item_name, quantity)
    @item_name = item_name
    @quantity = quantity
  end

end

item = Item.new("TV",2)
puts item.item_name
puts item.quantity

ไวยากรณ์นี้ทำงานในลักษณะเดียวกันเท่านั้น แต่จะช่วยเราหกบรรทัดของรหัส ลองนึกภาพถ้าคุณมีสถานะเพิ่มอีก 5 อันเนื่องมาจากคลาสรายการ รหัสจะยาวเร็ว

Setters, attr_writer: สิ่งที่ทำให้ฉันก้าวแรกด้วยวิธี setter คือในสายตาของฉันมันดูเหมือนจะทำหน้าที่เหมือนกันกับวิธีการเริ่มต้น ด้านล่างฉันอธิบายความแตกต่างตามความเข้าใจของฉัน

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

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

รหัสด้านล่างเป็นตัวอย่างของการใช้เมธอด setter เพื่อประกาศค่า item_name สำหรับอินสแตนซ์ของคลาสรายการ โปรดสังเกตว่าเรายังคงใช้วิธี getter ต่อไปเพื่อ attr_reader เพื่อให้เราสามารถรับค่าและพิมพ์ไปยังหน้าจอในกรณีที่คุณต้องการทดสอบรหัสด้วยตัวคุณเอง

class Item

attr_reader :item_name

  def item_name=(str)
    @item_name = (str)
  end

end

โค้ดด้านล่างเป็นตัวอย่างของการใช้ attr_writer เพื่อย่อรหัสของเราอีกครั้งและประหยัดเวลา

class Item

attr_reader :item_name
attr_writer :item_name

end

item = Item.new
puts item.item_name = "TV"

โค้ดด้านล่างเป็นการทำซ้ำของตัวอย่างการเริ่มต้นด้านบนที่เราใช้ initialize เพื่อตั้งค่าวัตถุของ item_name เมื่อสร้าง

class Item

attr_reader :item_name

  def initialize(item_name)
    @item_name = item_name
  end

end

item = Item.new("TV")
puts item.item_name

attr_accessor: ทำหน้าที่ของทั้ง attr_reader และ attr_writer ช่วยให้คุณประหยัดอีกหนึ่งบรรทัดของรหัส


10

ฉันคิดว่าส่วนหนึ่งของสิ่งที่สับสน Rubyists / โปรแกรมเมอร์ใหม่ (เหมือนตัวเอง) คือ:

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

พูดคุยทั่วไปมากกว่านี้เล็กน้อย แต่นี่คือวิธีการคลิกสำหรับฉัน:

ได้รับ:

class Person
end

เราไม่ได้กำหนดบุคคลเป็นสิ่งที่สามารถมีชื่อหรือคุณลักษณะอื่น ๆ

ดังนั้นหากเรา:

baby = Person.new

... และพยายามตั้งชื่อพวกเขา ...

baby.name = "Ruth"

เราได้รับข้อผิดพลาดเพราะใน Rubyland คลาสของวัตถุบุคคลนั้นไม่ใช่สิ่งที่เกี่ยวข้องหรือมี "ชื่อ" ... ยัง!

แต่เราสามารถใช้วิธีการใด ๆ ที่กำหนด (ดูคำตอบก่อนหน้า) เป็นวิธีที่จะพูดว่า "ตัวอย่างของคลาสบุคคล ( baby) ตอนนี้สามารถมีคุณลักษณะที่เรียกว่า 'ชื่อ' ดังนั้นเราไม่เพียงมีวิธีการรับและ ตั้งชื่อนั้น แต่มันสมเหตุสมผลสำหรับเราที่จะทำเช่นนั้น "

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


7

เพียงแค่ใส่มันจะกำหนดตัวตั้งค่าและทะเยอทะยานสำหรับชั้นเรียน

สังเกตได้ว่า

attr_reader :v is equivalant to 
def v
  @v
end

attr_writer :v is equivalant to
def v=(value)
  @v=value
end

ดังนั้น

attr_accessor :v which means 
attr_reader :v; attr_writer :v 

เทียบเท่ากับการกำหนด setter และทะเยอทะยานสำหรับชั้นเรียน


5

เพียงattr-accessorสร้างgetterและsetterวิธีการสำหรับแอตทริบิวต์ที่ระบุ


5

attr_accessorวิธีที่จะเข้าใจมันก็คือการคิดออกว่ารหัสข้อผิดพลาดลดโดยมี

ตัวอย่าง:

class BankAccount    
  def initialize( account_owner )
    @owner = account_owner
    @balance = 0
  end

  def deposit( amount )
    @balance = @balance + amount
  end

  def withdraw( amount )
    @balance = @balance - amount
  end
end

มีวิธีการดังต่อไปนี้:

$ bankie = BankAccout.new("Iggy")
$ bankie 
$ bankie.deposit(100)
$ bankie.withdraw(5)

วิธีการต่อไปนี้จะเกิดข้อผิดพลาด:

$ bankie.owner     #undefined method `owner'... 
$ bankie.balance   #undefined method `balance'...

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

การเพิ่มattr_accessor :balance, :ownerอนุญาตให้คุณอ่านและเขียนbalanceและowner"วิธีการ" ตอนนี้คุณสามารถใช้ 2 วิธีล่าสุด

$ bankie.balance
$ bankie.owner

2

กำหนดแอตทริบิวต์ที่มีชื่อสำหรับโมดูลนี้โดยที่ชื่อคือ symbol.id2name สร้างตัวแปรอินสแตนซ์ (@name) และวิธีการเข้าถึงที่สอดคล้องกันเพื่ออ่าน สร้างเมธอดชื่อ = เพื่อตั้งค่าแอ็ตทริบิวต์

module Mod
  attr_accessor(:one, :two)
end
Mod.instance_methods.sort   #=> [:one, :one=, :two, :two=]

1

เพื่อสรุปคุณสมบัติ accessor aka attr_accessor ให้สองวิธีฟรี

เช่นเดียวกับใน Java พวกมันถูกเรียกว่า getters และ setters

คำตอบมากมายแสดงตัวอย่างที่ดีดังนั้นฉันจะสรุป

#the_attribute

และ

# the_attribute =

ในเอกสารทับทิมเก่า hash tag # หมายถึงวิธีการ มันอาจรวมถึงคำนำหน้าชื่อชั้น ... MyClass # my_method


1

ฉันใหม่กับทับทิมและต้องจัดการกับความเข้าใจเรื่องประหลาดต่อไปนี้ อาจช่วยคนอื่นในอนาคต ในท้ายที่สุดมันเป็นดังกล่าวข้างต้นที่ 2 ฟังก์ชั่น (def myvar, def myvar =) ทั้งสองได้รับโดยปริยายสำหรับการเข้าถึง @ myvar แต่วิธีการเหล่านี้สามารถถูกแทนที่โดยการประกาศในท้องถิ่น

class Foo
  attr_accessor 'myvar'
  def initialize
    @myvar = "A"
    myvar = "B"
    puts @myvar # A
    puts myvar # B - myvar declared above overrides myvar method
  end

  def test
    puts @myvar # A
    puts myvar # A - coming from myvar accessor

    myvar = "C" # local myvar overrides accessor
    puts @myvar # A
    puts myvar # C

    send "myvar=", "E" # not running "myvar =", but instead calls setter for @myvar
    puts @myvar # E
    puts myvar # C
  end
end

0

คุณสมบัติและวิธีการ accessor

คุณสมบัติเป็นองค์ประกอบระดับที่สามารถเข้าถึงได้จากนอกวัตถุ พวกเขาเป็นที่รู้จักกันว่าคุณสมบัติในภาษาการเขียนโปรแกรมอื่น ๆ อีกมากมาย ค่าของพวกเขาสามารถเข้าถึงได้โดยใช้ "จุดสัญกรณ์" เช่นเดียวกับใน object_name.attribute_name แตกต่างจาก Python และภาษาอื่น ๆ สองสาม Ruby ไม่อนุญาตให้ตัวแปรอินสแตนซ์สามารถเข้าถึงได้โดยตรงจากนอกวัตถุ

class Car
  def initialize
    @wheels = 4  # This is an instance variable
  end
end

c = Car.new
c.wheels     # Output: NoMethodError: undefined method `wheels' for #<Car:0x00000000d43500>

ในตัวอย่างข้างต้น c เป็นตัวอย่าง (วัตถุ) ของคลาสรถยนต์ เราพยายามอ่านค่าตัวแปรอินสแตนซ์ของล้อจากนอกวัตถุไม่สำเร็จ สิ่งที่เกิดขึ้นคือทับทิมพยายามเรียกเมธอดชื่อล้อที่อยู่ภายในวัตถุ c แต่ไม่ได้กำหนดวิธีดังกล่าว ในระยะสั้น object_name.attribute_name พยายามเรียกวิธีชื่อ attribute_name ภายในวัตถุ ในการเข้าถึงค่าของตัวแปรล้อจากภายนอกเราจำเป็นต้องใช้เมธอดอินสแตนซ์โดยใช้ชื่อนั้นซึ่งจะส่งคืนค่าของตัวแปรนั้นเมื่อถูกเรียก ที่เรียกว่าวิธีการเข้าถึง ในบริบทการเขียนโปรแกรมทั่วไปวิธีการทั่วไปในการเข้าถึงตัวแปรอินสแตนซ์จากนอกวัตถุคือการใช้วิธีการเข้าถึงที่เรียกว่าวิธี getter และ setter

ในตัวอย่างต่อไปนี้เราได้เพิ่มวิธี getter และ setter ให้กับคลาส Car เพื่อเข้าถึงตัวแปรล้อจากนอกวัตถุ นี่ไม่ใช่ "วิธีการทับทิม" ของการกำหนด getters และ setters; มันทำหน้าที่เพียงเพื่อแสดงให้เห็นว่าสิ่งที่ getter และ setter วิธีการทำ

class Car
  def wheels  # getter method
    @wheels
  end

  def wheels=(val)  # setter method
    @wheels = val
  end
end

f = Car.new
f.wheels = 4  # The setter method was invoked
f.wheels  # The getter method was invoked
# Output: => 4

ตัวอย่างงานด้านบนและรหัสที่คล้ายกันมักใช้ในการสร้างวิธี getter และ setter ในภาษาอื่น อย่างไรก็ตาม Ruby มีวิธีที่ง่ายกว่าในการทำเช่นนี้: สามวิธีในตัวที่เรียกว่า attr_reader, attr_writer และ attr_acessor เมธอด attr_reader ทำให้ตัวแปรอินสแตนซ์สามารถอ่านได้จากภายนอก attr_writer ทำให้สามารถเขียนได้และ attr_acessor ทำให้สามารถอ่านและเขียนได้

ตัวอย่างด้านบนสามารถเขียนใหม่ได้เช่นนี้

class Car
  attr_accessor :wheels
end

f = Car.new
f.wheels = 4
f.wheels  # Output: => 4

ในตัวอย่างข้างต้นแอ็ตทริบิวต์ Wheels จะสามารถอ่านและเขียนได้จากนอกวัตถุ ถ้าแทนที่จะเป็น attr_accessor เราใช้ attr_reader มันจะเป็นแบบอ่านอย่างเดียว ถ้าเราใช้ attr_writer มันจะเป็นแบบเขียนอย่างเดียว วิธีการทั้งสามนั้นไม่ใช่ getters และ setters ในตัวเอง แต่เมื่อถูกเรียกมันจะสร้าง getter และ setter สำหรับเรา พวกเขาเป็นวิธีการที่สร้างแบบไดนามิก (โดยทางโปรแกรม) สร้างวิธีอื่น ๆ ; ที่เรียกว่า metaprogramming

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

เป็นไปได้ที่จะเข้าถึง (อ่านและเขียน) ตัวแปรอินสแตนซ์จากนอกวัตถุโดยใช้วิธีการ built-in instance_variable_get และ instance_variable_set อย่างไรก็ตามนี่เป็นเหตุผลที่ไม่ค่อยสมเหตุสมผลและมักเป็นความคิดที่ไม่ดีเนื่องจากการผ่านการห่อหุ้มมีแนวโน้มที่จะทำให้เกิดความเสียหายทุกประเภท


-2

อืมม คำตอบที่ดีมากมาย นี่คือไม่กี่เซ็นต์ของฉันกับมัน

  • attr_accessorเป็นวิธีง่าย ๆ ที่ช่วยเราในการทำความสะอาด ( DRY-ing ) ถึงวิธีการทำซ้ำgetter and setter

  • เพื่อให้เราสามารถมุ่งเน้นไปที่การเขียนตรรกะทางธุรกิจมากขึ้นและไม่ต้องกังวลกับ setters และ getters


-3

หน้าที่หลักของattr_accessorเหนือสิ่งอื่นคือความสามารถในการเข้าถึงข้อมูลจากไฟล์อื่น ๆ
ดังนั้นคุณมักจะมี attr_reader หรือ attr_writer แต่ข่าวดีก็คือว่า Ruby ช่วยให้คุณรวมสองสิ่งนี้เข้าด้วยกันกับ attr_accessor ฉันคิดว่ามันเป็นวิธีการของฉันไปเพราะมันโค้งมนมากขึ้นหรือหลากหลาย อย่าลืมว่าใน Rails นี่ถูกกำจัดไปแล้วเพราะมันทำเพื่อคุณในด้านหลัง ดังนั้นในคำอื่น ๆ : คุณควรใช้ attr_acitor มากกว่าอีกสองคนเพราะคุณไม่ต้องกังวลกับการเป็นคนเฉพาะเจาะจง accessor ครอบคลุมทุกอย่าง ฉันรู้ว่านี่เป็นคำอธิบายทั่วไปมากกว่า แต่มันช่วยฉันในฐานะมือใหม่

หวังว่านี่จะช่วยได้!

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