ruby - attr_reader - 龍哥git




Ruby中的attr_accessor是什麼? (12)

屬性和訪問器方法

屬性是可以從對像外部訪問的類組件。 它們被稱為許多其他編程語言的屬性。 它們的值可以通過使用“點符號”來訪問,如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是Car類的一個實例(對象)。 我們嘗試從對像外部讀取wheels實例變量的值,但嘗試失敗。 發生了什麼事是Ruby嘗試在c對象內調用一個名為wheels的方法,但是沒有定義這樣的方法。 簡而言之,object_name.attribute_name會嘗試在對象內調用名為attribute_name的方法。 要從外部訪問wheels變量的值,我們需要通過該名稱實現一個實例方法,該方法在調用時會返回該變量的值。 這就是所謂的訪問方法。 在一般的編程環境中,從對像外部訪問實例變量的常用方法是實現訪問器方法,也稱為getter和setter方法。 getter允許從外部讀取類中定義的變量的值,並且setter允許從外部寫入該值。

在以下示例中,我們將getter和setter方法添加到Car類以從對像外部訪問車輪變量。 這不是定義getter和setter的“Ruby方式”; 它僅用於說明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,它將是只寫的。 這三種方法本身不是獲取者和設置者,而是在被調用時為我們創建getter和setter方法。 它們是動態(編程)生成其他方法的方法; 這就是所謂的元編程。

第一個(較長)的例子,不使用Ruby的內置方法,只能在getter和setter方法需要額外的代碼時使用。 例如,在為實例變量賦值之前,setter方法可能需要驗證數據或進行一些計算。

通過使用instance_variable_get和instance_variable_set內置方法,可以從對像外部訪問(讀取和寫入)實例變量。 然而,這很少合理,通常是一個壞主意,因為繞過封裝往往會帶來各種各樣的破壞。

我很難理解Ruby中的attr_accessor 。 誰可以給我解釋一下這個?


attr_accessor 只是一種方法 。 (該鏈接應該提供更多關於它如何工作的信息 - 查看生成的方法對,並且教程應該告訴你如何使用它。)

訣竅是, class 不是 Ruby中的定義 (它僅僅是C ++和Java等語言中的一個定義),但它是一個表達式 。 正是在這個評估過程中,調用了attr_accessor方法,這又調整了當前類 - 記住隱式接收方: self.attr_accessor ,其中self是此時的“open”類對象。

attr_accessor和朋友的需求,很好:

  1. Ruby和Smalltalk一樣,不允許在該對象的方法1之外訪問實例變量。 也就是說,實例變量無法以xy格式訪問,就像在Java或甚至Python中常見的那樣。 在Ruby中, y總是作為一個消息發送(或“調用方法”)。 因此, attr_*方法通過動態創建的方法創建代理實例@variable訪問的包裝器。

  2. 鍋板很爛

希望能夠澄清一些小的細節。 快樂的編碼。

1這並非嚴格意義上的,這裡有一些“技巧” ,但是沒有對“公共實例變量”訪問的語法支持。


attr_accessor非常簡單:

attr_accessor :foo

是一個捷徑:

def foo=(val)
  @foo = val
end

def foo
  @foo
end

它只不過是一個對象的getter / setter


attr_accessor與其他文件的主要功能是從其他文件訪問數據的功能。
所以你通常會有attr_reader或attr_writer,但好消息是Ruby允許你將這兩者與attr_accessor結合在一起。 我認為這是我的方法,因為它更全面或多功能。 另外,請記住,在Rails中,這被淘汰,因為它在後端為你做。 換句話說:您最好使用attr_acessor而不是另外兩個,因為您不必擔心特定的問題,訪問者可以覆蓋所有這些。 我知道這更多的是一般性解釋,但它幫助我成為初學者。

希望這有助於!


只需attr-accessor為指定的屬性創建gettersetter方法


嗯。 很多好的答案。 這是我的幾分錢。

  • attr_accessor是一個簡單的方法,可以幫助我們清理( DRY重複的getter and setter方法。

  • 這樣我們就可以更專注於編寫業務邏輯,而不用擔心安裝者和獲取者。


大多數上述答案使用代碼。 此解釋試圖在不使用任何代碼的情況下回答它:

通過類比解釋

外部黨派不能訪問內部中央情報局的秘密

  • 讓我們想像一個非常隱秘的地方:中央情報局。 除了中央情報局的人員外,沒有人知道中央情報局正在發生什麼。 換句話說,外部人不能訪問CIA中的任何信息。 但是因為擁有一個完全秘密的組織並不是一件好事,某些信息可以提供給外部世界 - 只有中情局當然希望每個人都知道的事情:例如中情局局長,這個部門的環境友好程度如何所有其他政府部門等。其他信息:例如,誰是在伊拉克或阿富汗的秘密行動者 - 這些類型的事情可能在未來150年內保持秘密。

  • 如果你在CIA之外,你只能訪問它提供給公眾的信息。 或者使用CIA的說法,您只能訪問“已清除”的信息。

  • 中央情報局希望提供給中央情報局以外的公眾的信息稱為: 屬性。

讀寫屬性的含義:

  • 在CIA的情況下,大多數屬性是“只讀”的。 這意味著如果你是中央情報局外部的一方,你可以問: “中情局局長是誰?” 你會得到一個直接的答案。 但是,“只讀”屬性無法做到的是在CIA中進行更改。 例如,你不能打個電話,並突然決定你想讓Kim Kardashian當導演,或者你希望Paris Hilton成為總司令。

  • 如果屬性給了你“寫入”權限,那麼即使你在外面,你也可以做出改變。 否則,你唯一能做的就是閱讀。

    換言之,訪問者允許您向不允許外部人員進入的組織進行查詢或進行更改,具體取決於訪問者是讀取還是寫入訪問者。

類內的對象可以很容易地訪問對方

  • 另一方面,如果你已經進入中央情報局,那麼你可以輕鬆地打電話給你在喀布爾的中央情報局工作人員,並詢問他下班後是否想與當地喀布爾的知情人一起喝啤酒。 但是如果你不在中央情報局,你根本就不會獲得訪問權限:你將無法知道他們是誰(讀取權限),並且你將無法改變他們的使命(寫入權限)。

與類完全相同的東西以及你訪問變量,屬性和方法的能力。 HTH! 如有任何問題,請詢問我希望我能澄清。


如果你熟悉OOP概念,你必須熟悉getter和setter方法。 attr_accessor在Ruby中也是這樣。

以一般方式吸氣和吸氣

class Person
  def name
    @name
  end

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

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

Setter方法

def name=(val)
  @name = val
end

Getter方法

def name
  @name
end

Ruby中的Getter和Setter方法

class Person
  attr_accessor :name
end

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

我也遇到了這個問題,並為這個問題寫了一個很長的回答。 對此已有一些很好的答案,但任何尋求更多解釋的人,我都希望我的答案能夠提供幫助

初始化方法

初始化允許您在創建實例時將數據設置為對象的實例,而不必在每次創建類的新實例時將其設置在代碼中的單獨一行中。

class Person
  attr_accessor :name

  def initialize(name)
    @name = name
  end


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

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

在上面的代碼中,我們使用initialize方法通過在Initialize中傳遞Dennis參數來設置名稱“Denis”。 如果我們想在不使用初始化方法的情況下設置名稱,我們可以這樣做:

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

在上面的代碼中,我們使用person.name調用attr_accessor setter方法來設置名稱,而不是在初始化對象時設置值。

這兩種“方法”的工作,但初始化為我們節省了時間和代碼行。

這是初始化的唯一工作。 您不能將初始化作為方法調用。 要真正獲取實例對象的值,需要使用getter和setter(attr_reader(get),attr_writer(set)和attr_accessor(both))。 請參閱下面的更多細節。

Getters,Setters(attr_reader,attr_writer,attr_accessor)

Getters,attr_reader:getter的全部目的是返回特定實例變量的值。 請訪問下面的示例代碼以了解這方面的細節。

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

在上面的代碼中,您正在項目“example”的實例上調用方法“item_name”和“quantity”。 “puts 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個更多的國家可歸於Item類? 代碼會很快變長。

Setter,attr_writer:最初用setter方法交叉我的是,在我看來,它似乎執行與初始化方法相同的功能。 下面我根據我的理解來解釋這種差異。

如前所述,initialize方法允許您在創建對象時設置對象實例的值。

但是如果你想在實例創建之後設置這些值,或者在初始化後更改這些值呢? 這將是一個你會使用setter方法的場景。 這是不同之處。 當您最初使用attr_writer方法時,您不必“設置”特定狀態。

下面的代碼是使用setter方法為Item類的此實例聲明值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"

下面的代碼是我們在創建時使用初始化來設置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的函數,為您節省一行代碼。


我認為混淆Ruby的新手/程序員(像我自己)的一部分是:

“為什麼我不能告訴實例它有任何給定的屬性(例如名稱),並且一次性給這個屬性賦值?”

有點更一般化,但這是它為我點擊​​的方式:

鑑於:

class Person
end

我們還沒有將Person定義為可以具有該名稱或任何其他屬性的事物。

所以如果我們那麼:

baby = Person.new

...並嘗試給他們一個名字......

baby.name = "Ruth"

我們得到一個錯誤,因為在Rubyland中,一個Person類的對象並不是與某個“名稱”相關聯或者能夠擁有“名稱”的東西......但是!

但是我們可以使用任何給定的方法(參見之前的答案)來說,“一個Person類的實例( baby現在可以有一個名為'name'的屬性,因此我們不僅具有語法並設置這個名字,但這對我們來說是合情合理的。“

再次,從一個稍微不同的,更一般的角度觸及這個問題,但我希望這有助於下一個Person類的下一個實例,他找到了這個線程的方式。


理解它的另一種方法是通過使用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'...

ownerbalance在技​​術上不是一種方法 ,而是一種屬性。 BankAccount類沒有def ownerdef balance 。 如果是這樣,那麼你可以使用下面的兩個命令。 但是這兩種方法都不存在。 但是,您可以像訪問通過attr_accessor的方法一樣訪問屬性! 因此這個詞attr_accessor 。 屬性。 訪問。 它像訪問一個方法一樣訪問屬性。

添加attr_accessor :balance, :owner允許您讀寫balanceowner “方法”。 現在你可以使用最後2種方法。

$ bankie.balance
$ bankie.owner

簡單地說,它將為班級定義一個setter和getter。

注意

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和getter。





ruby