Attr_accessor trong Ruby là gì?


1024

Tôi đang có một thời gian khó hiểu attr_accessortrong Ruby .
Ai đó có thể giải thích điều này với tôi?



1
Liệu attr_accessor có hoạt động theo cách tương tự trong Git không? Tôi thấy rằng một số hướng dẫn không giải thích đủ và những người khác thừa nhận kiến ​​thức trước.
Angelfirenze

10
@Angelfirenze, gitkhông có gì để làm attr_accessor. Git là một phần mềm kiểm soát phiên bản, trong khi đó attr_accessorlà một phương pháp trong Ruby .
Uzbekjon

Câu trả lời:


2360

Giả sử bạn có một lớp học Person.

class Person
end

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

Rõ ràng chúng tôi không bao giờ định nghĩa phương pháp name. Hãy làm điều đó.

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

Aha, chúng ta có thể đọc tên, nhưng điều đó không có nghĩa là chúng ta có thể gán tên. Đó là hai phương pháp khác nhau. Cái trước được gọi là người đọc và cái sau được gọi là nhà văn . Chúng tôi chưa tạo ra nhà văn nên chúng ta hãy làm điều đó.

class Person
  def name
    @name
  end

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

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

Tuyệt vời. Bây giờ chúng ta có thể viết và đọc biến thể hiện @namebằng các phương thức đọc và ghi. Ngoại trừ, điều này được thực hiện rất thường xuyên, tại sao lại lãng phí thời gian để viết các phương pháp này mỗi lần? Chúng tôi có thể làm điều đó dễ dàng hơn.

class Person
  attr_reader :name
  attr_writer :name
end

Thậm chí điều này có thể nhận được lặp đi lặp lại. Khi bạn muốn cả người đọc và người viết chỉ cần sử dụng accessor!

class Person
  attr_accessor :name
end

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

Hoạt động theo cách tương tự! Và đoán xem: biến @nameđối tượng trong đối tượng người của chúng ta sẽ được đặt giống như khi chúng ta thực hiện thủ công, vì vậy bạn có thể sử dụng nó trong các phương thức khác.

class Person
  attr_accessor :name

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

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

Đó là nó. Để hiểu làm thế nào attr_reader, attr_writerattr_accessorphương pháp thực sự tạo ra phương pháp cho bạn, đọc câu trả lời khác, sách, tài liệu ruby.


46
@hakunin - cảm ơn bạn đã trả lời rõ ràng. Điều còn thiếu đối với tôi là tại sao cú pháp Ruby gợi ý dấu hai chấm ':' cho các biến thể hiện trong câu lệnh attr_ *? Có vẻ như sẽ dễ dàng hơn khi sử dụng cùng một cú pháp '@' được sử dụng ở nơi khác trong lớp để tham chiếu đến biến.
Sẽ

207
@WilliamSmith Để trả lời câu hỏi của bạn, bạn cần hiểu đó attr_accessorlà một phương thức được gọi trên lớp hiện tại và :namelà một tham số bạn truyền cho phương thức đó. Đây không phải là một cú pháp đặc biệt, đó là một cuộc gọi phương thức đơn giản. Nếu bạn cho nó @namebiến, nó sẽ không có ý nghĩa, bởi vì @name sẽ chứa nil. Vì vậy, nó sẽ giống như viết attr_accessor nil. Bạn không truyền cho nó một biến mà nó cần tạo, bạn đang truyền tên mà bạn muốn biến đó được gọi.
Max Chernyak

23
@hakunin - Điều đó hoàn toàn có ý nghĩa. Hôm nay tôi mới biết rằng ruby ​​thực sự là 'đang chạy' vì nó phân tích cú pháp thông qua một tệp và mọi câu lệnh và biểu thức thực sự là một phương thức gọi một số đối tượng. Bao gồm attr_accessor. Rất hữu ích.
Sẽ

52
sử dụng Rails trong 3 năm, thậm chí không bao giờ biết điều này. Xấu hổ
Sean Xiao

5
@Buminda có, nhưng phương thức namevà biến @namekhông giống nhau. Đừng nhầm lẫn chúng. Bạn có biến đối tượng @nametrong lớp và bạn xác định attr_reader :nameđể có thể đọc nó từ bên ngoài. Không attr_readercó cách đơn giản, bạn có thể truy cập @namebên ngoài lớp học của bạn.
Max Chernyak

127

attr_accessorchỉ là một phương pháp . (Liên kết sẽ cung cấp cái nhìn sâu sắc hơn về cách thức hoạt động của nó - nhìn vào các cặp phương thức được tạo và một hướng dẫn sẽ chỉ cho bạn cách sử dụng nó.)

Bí quyết là rằng classkhông phải là một định nghĩa trong Ruby (nó là "chỉ là một định nghĩa" bằng các ngôn ngữ như C ++ và Java), nhưng nó là một biểu hiện mà đánh giá lại . Đó là trong quá trình đánh giá này khi attr_accessorphương thức được gọi, lần lượt sửa đổi lớp hiện tại - hãy nhớ người nhận ẩn : self.attr_accessor, selfđối tượng lớp "mở" ở điểm này.

Nhu cầu attr_accessorvà bạn bè, là, tốt:

  1. Ruby, như Smalltalk, không cho phép các biến thể hiện được truy cập bên ngoài các phương thức 1 cho đối tượng đó. Đó là, các biến thể hiện không thể được truy cập x.ydưới dạng như thông thường trong Java, hoặc thậm chí Python. Trong Ruby yluôn được coi là một thông điệp để gửi (hoặc "phương thức để gọi"). Do đó, các attr_*phương thức tạo các hàm bao mà proxy @variabletruy cập thể hiện thông qua các phương thức được tạo động.

  2. Nồi hơi hút

Hy vọng điều này làm rõ một số chi tiết nhỏ. Chúc mừng mã hóa.


1 Điều này không hoàn toàn đúng và có một số "kỹ thuật" xung quanh vấn đề này , nhưng không có hỗ trợ cú pháp cho truy cập "biến thể hiện công khai".


Khi bạn nói attr_accessor là "chỉ là một phương thức" tôi hiểu rồi. Nhưng cú pháp được sử dụng để gọi phương thức đó được gọi là gì? Tôi gặp khó khăn khi tìm phần trong tài liệu ruby ​​nói về cú pháp như some_method: name => "anything" ,: notherName ,: vv
BT

68

attr_accessorlà (như @pst đã nêu) chỉ là một phương thức. Những gì nó làm là tạo ra nhiều phương pháp cho bạn.

Vì vậy, mã này ở đây:

class Foo
  attr_accessor :bar
end

tương đương với mã này:

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

Bạn có thể tự viết loại phương thức này trong 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
Đây là một ví dụ tuyệt vời về việc siêu lập trình được sử dụng trong các kịch bản cấp độ mới bắt đầu nhất. Rất đẹp.
John Simon

2
Tôi đã tìm kiếm một bản phác thảo thực hiện attr_accessorvà cuối cùng được tìm thấy ở đây! Mặc dù nó đã giải quyết vấn đề của tôi, nhưng tôi tò mò muốn biết nơi nào (cuốn sách / tài liệu chính thức) tôi có thể tìm thấy một ví dụ triển khai như thế này?
Wasif Hossain

40

attr_accessor rất đơn giản:

attr_accessor :foo

là một phím tắt cho:

def foo=(val)
  @foo = val
end

def foo
  @foo
end

nó không có gì hơn một getter / setter cho một đối tượng


10
Câu trả lời của bạn là tốt. 'Phím tắt' có nghĩa là "một tuyến đường thay thế ngắn hơn" theo từ điển của tôi, không phải là "cú pháp đường" hay "macro được phiên dịch bởi trình thông dịch".
bowsersenior

25

Về cơ bản, chúng giả mạo các thuộc tính dữ liệu có thể truy cập công khai, mà Ruby không có.


4
Mặc dù nhận xét này không hoàn toàn hữu ích, nhưng đó là sự thật. Làm nổi bật thực tế là các thuộc tính dữ liệu công cộng không tồn tại bên ngoài các phương thức "get" trong Ruby, đây là thông tin thực sự hữu ích cho ai đó đang cố gắng học ngôn ngữ.
Eric Dand

3
Điều này thực sự không nên bị hạ thấp. Là một người không phải là Ruby đang cố gắng tìm ra thứ này, câu trả lời này rất hữu ích!
Brad

1
Đồng ý, có vẻ rất giống với tên của C # {get; thiết lập;}
David Miler 23/12/13

17

Nó chỉ là một phương thức định nghĩa các phương thức getter và setter cho các biến thể hiện. Một ví dụ thực hiện sẽ là:

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

xử lý nhiều thuộc tính theo cách này là tuyệt vời!
Wasif Hossain

Đây là một đoạn mã thực sự hữu ích để giải quyết một câu hỏi khác mà tôi có liên quan đến siêu lập trình.
alexventuraio

15

Giải thích đơn giản mà không cần bất kỳ mã

Hầu hết các câu trả lời trên sử dụng mã. Giải thích này cố gắng trả lời nó mà không sử dụng bất kỳ, thông qua một câu chuyện tương tự:

Các bên ngoài không thể truy cập các bí mật nội bộ của CIA

  • Hãy tưởng tượng một nơi thực sự bí mật: CIA. Không ai biết những gì đang xảy ra trong CIA ngoài những người bên trong CIA. Nói cách khác, những người bên ngoài không thể truy cập bất kỳ thông tin nào trong CIA. Nhưng vì không có tổ chức nào hoàn toàn bí mật, một số thông tin nhất định được cung cấp cho thế giới bên ngoài - chỉ những điều mà CIA muốn mọi người biết về tất nhiên: ví dụ: Giám đốc CIA, bộ phận này thân thiện với môi trường như thế nào cho tất cả các cơ quan chính phủ khác, v.v. Thông tin khác: ví dụ như những người hoạt động bí mật ở Iraq hoặc Afghanistan - những loại điều này có thể sẽ vẫn là bí mật trong 150 năm tới.

  • Nếu bạn ở ngoài CIA, bạn chỉ có thể truy cập thông tin mà nó đã cung cấp cho công chúng. Hoặc để sử dụng cách nói của CIA, bạn chỉ có thể truy cập thông tin bị "xóa".

  • Thông tin mà CIA muốn cung cấp cho công chúng bên ngoài CIA được gọi là: thuộc tính.

Ý nghĩa của các thuộc tính đọc và viết:

  • Trong trường hợp của CIA, hầu hết các thuộc tính là "chỉ đọc". Điều này có nghĩa là nếu bạn là một bên ngoài CIA, bạn có thể hỏi: "ai là giám đốc của CIA?" và bạn sẽ nhận được một câu trả lời thẳng. Nhưng điều bạn không thể làm với các thuộc tính "chỉ đọc" là thực hiện các thay đổi thay đổi trong CIA. ví dụ: bạn không thể gọi điện thoại và đột nhiên quyết định rằng bạn muốn Kim Kardashian làm Giám đốc hoặc bạn muốn Paris Hilton trở thành Tổng tư lệnh.

  • Nếu các thuộc tính cho bạn quyền truy cập "ghi", thì bạn có thể thay đổi nếu bạn muốn, ngay cả khi bạn ở bên ngoài. Nếu không, điều duy nhất bạn có thể làm là đọc.

    Nói cách khác, người truy cập cho phép bạn thực hiện yêu cầu hoặc thực hiện thay đổi đối với các tổ chức không cho phép người bên ngoài vào, tùy thuộc vào việc người truy cập được đọc hoặc viết người truy cập.

Các đối tượng trong một lớp có thể dễ dàng truy cập lẫn nhau

  • Mặt khác, nếu bạn đã ở trong CIA, thì bạn có thể dễ dàng gọi cho CIA của bạn ở Kabul vì thông tin này có thể dễ dàng truy cập nếu bạn đã ở trong đó. Nhưng nếu bạn ở ngoài CIA, bạn sẽ không được cấp quyền truy cập: bạn sẽ không thể biết họ là ai (truy cập đọc) và bạn sẽ không thể thay đổi nhiệm vụ của họ (quyền truy cập viết).

Chính xác điều tương tự với các lớp và khả năng của bạn để truy cập các biến, thuộc tính và phương thức trong chúng. HTH! Bất kỳ câu hỏi, xin vui lòng hỏi và tôi hy vọng tôi có thể làm rõ.


Giải thích của bạn có ý nghĩa! +1 Xin lỗi, bạn có chắc rằng biểu thức "thông tin bị xóa bởi CIA là đúng không?
kouty

có nhiều cấp độ "giải phóng mặt bằng" khác nhau trong CIA: ví dụ: Bí mật hàng đầu (không ai ngoài Prez) hoặc niềm tin của công chúng (mọi người đều có thể đọc thông tin đó). CIA thực sự cung cấp rất nhiều sự thật rất hay!
BKSpurgeon

Bạn xứng đáng với sự ủng hộ chỉ dành cho các ví dụ của Kardashian, Paris Hilton :) Tôi nghĩ rằng điều đó đủ tồi tệ với Trump đối với Tổng thống, hãy tưởng tượng hai người đó chịu trách nhiệm!
rmcsharry

Đúng! Đó là những gì chúng ta cần, StackOverflow không có mã! :-)
Marvin

13

Nếu bạn quen thuộc với khái niệm OOP, Bạn phải làm quen với phương thức getter và setter. attr_accessor cũng làm như vậy trong Ruby.

Getter và Setter theo cách chung

class Person
  def name
    @name
  end

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

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

Phương pháp Setter

def name=(val)
  @name = val
end

Phương pháp Getter

def name
  @name
end

Phương pháp Getter và Setter trong Ruby

class Person
  attr_accessor :name
end

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

2
giải thích hoàn hảo! Đó là một hành vi rất tiện dụng và có thể bị ghi đè quá dễ dàng.
Rubyrider 8/2/2015

12

Tôi cũng phải đối mặt với vấn đề này và đã viết một câu trả lời hơi dài cho câu hỏi này. Có một số câu trả lời tuyệt vời về điều này đã có, nhưng bất cứ ai đang tìm kiếm làm rõ hơn, tôi hy vọng câu trả lời của tôi có thể giúp

Phương thức khởi tạo

Khởi tạo cho phép bạn đặt dữ liệu thành một thể hiện của một đối tượng khi tạo cá thể thay vì phải đặt chúng trên một dòng riêng trong mã của bạn mỗi khi bạn tạo một thể hiện mới của lớp.

class Person

  def initialize(name)
    @name = name
  end


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

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

Trong đoạn mã trên, chúng tôi đang đặt tên là Denis Denis Tiết bằng cách sử dụng phương thức khởi tạo bằng cách chuyển Dennis qua tham số trong Khởi tạo. Nếu chúng ta muốn đặt tên mà không có phương thức khởi tạo, chúng ta có thể làm như vậy:

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

Trong đoạn mã trên, chúng tôi đặt tên bằng cách gọi phương thức setter attr_accessor bằng person.name, thay vì đặt các giá trị khi khởi tạo đối tượng.

Cả hai phương thức của Cameron đều thực hiện công việc này, nhưng khởi tạo giúp chúng ta tiết kiệm thời gian và dòng mã.

Đây là công việc duy nhất của khởi tạo. Bạn không thể gọi khởi tạo như một phương thức. Để thực sự có được các giá trị của một đối tượng thể hiện, bạn cần sử dụng getters và setters (attr_reader (get), attr_writer (set) và attr_accessor (cả hai)). Xem bên dưới để biết thêm chi tiết về những người.

Getters, Setters (attr_reader, attr_writer, attr_accessor)

Getters, attr_reader: Toàn bộ mục đích của getter là trả về giá trị của một biến đối tượng cụ thể. Truy cập mã mẫu dưới đây để biết chi tiết về điều này.

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

Trong đoạn mã trên, bạn đang gọi các phương thức. Các trò chơi đưa ra example.item_name và ví dụ.quantity, sẽ trả về (hoặc có thể nhận được) giá trị cho các tham số được truyền vào ví dụ về các ví dụ và hiển thị chúng trên màn hình.

May mắn thay trong Ruby có một phương thức vốn có cho phép chúng ta viết mã này ngắn gọn hơn; phương thức attr_reader. Xem mã dưới đây;

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

Cú pháp này hoạt động chính xác theo cùng một cách, chỉ có điều nó giúp chúng ta tiết kiệm sáu dòng mã. Hãy tưởng tượng nếu bạn có thêm 5 trạng thái quy cho lớp Item? Mã sẽ nhận được lâu dài.

Setters, attr_writer: Điều đầu tiên vượt qua tôi với các phương thức setter là trong mắt tôi dường như nó thực hiện một chức năng giống hệt với phương thức khởi tạo. Dưới đây tôi giải thích sự khác biệt dựa trên sự hiểu biết của tôi;

Như đã nêu trước đây, phương thức khởi tạo cho phép bạn đặt các giá trị cho một thể hiện của một đối tượng khi tạo đối tượng.

Nhưng nếu bạn muốn đặt các giá trị sau này, sau khi thể hiện được tạo hoặc thay đổi chúng sau khi chúng được khởi tạo thì sao? Đây sẽ là một kịch bản trong đó bạn sẽ sử dụng một phương thức setter. ĐÓ LÀ SỰ KHÁC BIỆT. Bạn không cần phải thiết lập một trạng thái cụ thể khi bạn đang sử dụng phương thức attr_writer.

Mã dưới đây là một ví dụ về việc sử dụng phương thức setter để khai báo giá trị item_name cho trường hợp này của lớp Item. Lưu ý rằng chúng tôi tiếp tục sử dụng phương thức getter attr_reader để chúng tôi có thể nhận các giá trị và in chúng ra màn hình, chỉ trong trường hợp bạn muốn tự mình kiểm tra mã.

class Item

attr_reader :item_name

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

end

Mã dưới đây là một ví dụ về việc sử dụng attr_writer để một lần nữa rút ngắn mã của chúng tôi và tiết kiệm thời gian cho chúng tôi.

class Item

attr_reader :item_name
attr_writer :item_name

end

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

Mã dưới đây là một sự lặp lại của ví dụ khởi tạo ở trên nơi chúng ta đang sử dụng khởi tạo để đặt giá trị đối tượng của item_name khi tạo.

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: Thực hiện các chức năng của cả attr_reader và attr_writer, giúp bạn tiết kiệm thêm một dòng mã.


10

Tôi nghĩ rằng một phần của những gì nhầm lẫn Rubyists / lập trình viên mới (như bản thân tôi) là:

"Tại sao tôi không thể nói với trường hợp nó có bất kỳ thuộc tính đã cho nào (ví dụ: tên) và cung cấp cho thuộc tính đó một giá trị trong một swoop?"

Tổng quát hơn một chút, nhưng đây là cách nó đã nhấp cho tôi:

Được:

class Person
end

Chúng tôi chưa định nghĩa Người là một cái gì đó có thể có tên hoặc bất kỳ thuộc tính nào khác cho vấn đề đó.

Vì vậy, nếu chúng ta sau đó:

baby = Person.new

... và cố gắng đặt cho họ một cái tên ...

baby.name = "Ruth"

Chúng tôi gặp lỗi vì, trong Rubyland, một lớp đối tượng Person không phải là thứ có liên quan hoặc có khả năng có "tên" ...!

NHƯNG chúng ta có thể sử dụng bất kỳ phương thức đã cho nào (xem các câu trả lời trước) như một cách để nói, "Một thể hiện của lớp Person ( baby) giờ đây có thể có một thuộc tính được gọi là 'name', do đó chúng ta không chỉ có một cách tổng hợp để nhận và đặt tên đó, nhưng thật hợp lý khi chúng ta làm như vậy. "

Một lần nữa, đánh vào câu hỏi này từ một góc độ hơi khác và chung chung hơn, nhưng tôi hy vọng điều này sẽ giúp cho cá thể lớp tiếp theo tìm được đường đến chủ đề này.


7

Đơn giản chỉ cần đặt nó sẽ định nghĩa một setter và getter cho lớp.

Lưu ý rằng

attr_reader :v is equivalant to 
def v
  @v
end

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

Vì thế

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

là tương đương để định nghĩa một setter và getter cho lớp.


5

Chỉ cần attr-accessortạo gettersettercác phương thức cho các thuộc tính được chỉ định


5

Một cách khác để hiểu nó là tìm ra mã lỗi nào loại bỏ bằng cách có attr_accessor.

Thí dụ:

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

Các phương pháp sau đây có sẵn:

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

Các phương pháp sau đây ném lỗi:

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

ownerbalancekhông phải là, về mặt kỹ thuật, một phương pháp , nhưng một thuộc tính. Lớp BankAccount không có def ownerdef balance. Nếu vậy, bạn có thể sử dụng hai lệnh dưới đây. Nhưng hai phương pháp đó không có ở đó. Tuy nhiên, bạn có thể truy cập các thuộc tính như thể bạn truy cập một phương thức thông qua attr_accessor!! Do đó từattr_accessor . Thuộc tính. Phụ kiện. Nó truy cập các thuộc tính như bạn sẽ truy cập một phương thức.

Thêm attr_accessor :balance, :ownercho phép bạn đọc và viết balanceowner"phương pháp". Bây giờ bạn có thể sử dụng 2 phương pháp cuối cùng.

$ bankie.balance
$ bankie.owner

2

Xác định một thuộc tính được đặt tên cho mô-đun này, trong đó tên là Symbol.id2name, tạo một biến thể hiện (@name) và một phương thức truy cập tương ứng để đọc nó. Cũng tạo một phương thức gọi là name = để đặt thuộc tính.

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

1

Để tóm tắt một trình truy cập thuộc tính aka attr_accessor cung cấp cho bạn hai phương thức miễn phí.

Giống như trong Java, chúng được gọi là getters và setters.

Nhiều câu trả lời đã cho thấy những ví dụ hay vì vậy tôi sẽ nói ngắn gọn.

#the_attribution

# the_attribution =

Trong các tài liệu ruby ​​cũ, thẻ băm # có nghĩa là một phương thức. Nó cũng có thể bao gồm tiền tố tên lớp ... MyClass # my_method


1

Tôi mới làm quen với ruby ​​và phải đối phó với sự hiểu biết về sự kỳ lạ sau đây. Có thể giúp đỡ người khác trong tương lai. Cuối cùng, như đã đề cập ở trên, trong đó 2 hàm (def myvar, def myvar =) đều được ngầm định truy cập @myvar, nhưng các phương thức này có thể bị ghi đè bởi khai báo cục bộ.

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

Các thuộc tính và phương thức truy cập

Các thuộc tính là các thành phần lớp có thể được truy cập từ bên ngoài đối tượng. Chúng được gọi là thuộc tính trong nhiều ngôn ngữ lập trình khác. Các giá trị của chúng có thể truy cập được bằng cách sử dụng "ký hiệu dấu chấm", như trong object_name.attribution_name. Không giống như Python và một vài ngôn ngữ khác, Ruby không cho phép các biến thể hiện được truy cập trực tiếp từ bên ngoài đối tượng.

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>

Trong ví dụ trên, c là một thể hiện (đối tượng) của lớp Car. Chúng tôi đã cố gắng không thành công để đọc giá trị của biến đối tượng bánh xe từ bên ngoài đối tượng. Điều đã xảy ra là Ruby đã cố gắng gọi một phương thức có tên là các bánh xe trong đối tượng c, nhưng không có phương thức nào được xác định. Nói tóm lại, object_name.attribution_name cố gắng gọi một phương thức có tên property_name bên trong đối tượng. Để truy cập giá trị của biến bánh xe từ bên ngoài, chúng ta cần triển khai một phương thức thể hiện bằng tên đó, nó sẽ trả về giá trị của biến đó khi được gọi. Đó gọi là phương pháp truy cập. Trong ngữ cảnh lập trình chung, cách thông thường để truy cập một biến đối tượng từ bên ngoài đối tượng là triển khai các phương thức truy cập, còn được gọi là phương thức getter và setter.

Trong ví dụ sau, chúng tôi đã thêm các phương thức getter và setter vào lớp Car để truy cập biến bánh xe từ bên ngoài đối tượng. Đây không phải là "cách Ruby" để xác định getters và setters; nó chỉ phục vụ để minh họa những gì phương thức getter và setter làm.

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

Ví dụ trên hoạt động và mã tương tự thường được sử dụng để tạo các phương thức getter và setter trong các ngôn ngữ khác. Tuy nhiên, Ruby cung cấp một cách đơn giản hơn để làm điều này: ba phương thức tích hợp được gọi là attr_reader, attr_writer và attr_acigator. Phương thức attr_reader làm cho một biến đối tượng có thể đọc được từ bên ngoài, attr_writer làm cho nó có thể ghi được và attr_acigator làm cho nó có thể đọc và ghi được.

Ví dụ trên có thể được viết lại như thế này.

class Car
  attr_accessor :wheels
end

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

Trong ví dụ trên, thuộc tính bánh xe sẽ có thể đọc và ghi được từ bên ngoài đối tượng. Nếu thay vì attr_accessor, chúng tôi đã sử dụng attr_reader, nó sẽ chỉ đọc. Nếu chúng ta sử dụng attr_writer, nó sẽ chỉ ghi. Ba phương thức đó không phải là getters và setters trong chính chúng, nhưng khi được gọi, chúng tạo ra các phương thức getter và setter cho chúng ta. Chúng là các phương thức tự động (lập trình) tạo ra các phương thức khác; đó gọi là siêu lập trình.

Ví dụ đầu tiên (dài hơn), không sử dụng các phương thức dựng sẵn của Ruby, chỉ nên được sử dụng khi cần thêm mã trong các phương thức getter và setter. Ví dụ, một phương thức setter có thể cần xác thực dữ liệu hoặc thực hiện một số tính toán trước khi gán giá trị cho một biến thể hiện.

Có thể truy cập (đọc và ghi) các biến đối tượng từ bên ngoài đối tượng, bằng cách sử dụng các phương thức dựng sẵn instance_variable_get và instance_variable_set. Tuy nhiên, điều này hiếm khi chính đáng và thường là một ý tưởng tồi, vì bỏ qua việc đóng gói có xu hướng tàn phá tất cả các loại tàn phá.


-2

Hừm. Rất nhiều câu trả lời hay. Đây là vài xu của tôi về nó.

  • attr_accessorlà một phương pháp đơn giản giúp chúng ta làm sạch ( DRY-ing ) lên các phương thức lặp lạigetter and setter .

  • Vì vậy, chúng ta có thể tập trung nhiều hơn vào việc viết logic kinh doanh và không phải lo lắng về các setters và getters.


-3

Chức năng chính của attr_accessor so với các ứng dụng khác là khả năng truy cập dữ liệu từ các tệp khác.
Vì vậy, bạn thường sẽ có attr_reader hoặc attr_writer nhưng tin tốt là Ruby cho phép bạn kết hợp hai thứ này với nhau với attr_accessor. Tôi nghĩ về nó như là phương pháp để đi của tôi bởi vì nó được làm tròn tốt hơn hoặc linh hoạt hơn. Ngoài ra, hãy nhớ rằng trong Rails, điều này bị loại bỏ bởi vì nó làm điều đó cho bạn ở phần cuối. Vì vậy, nói cách khác: bạn nên sử dụng attr_acigator hơn hai người kia vì bạn không phải lo lắng về việc cụ thể, người truy cập bao gồm tất cả. Tôi biết đây là một lời giải thích chung hơn nhưng nó đã giúp tôi như một người mới bắt đầu.

Hy vọng điều này sẽ giúp!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.