![](/img/trans.png)
[英]Ruby on Rails - Can I modify the value of an attribute before it is called?
[英]Ruby Modify Argument Value
我現在正在Ruby中練習小寫,並嘗試根據傳遞給相同方法的另一個參數來修改參數的值。 但是,它根本不起作用。
例如:
class Duck
attr_reader :foo, :bar
def initialize
@foo = false
@bar = false
end
def duck_foo
ducktype(@foo, @bar)
end
def duck_bar
ducktype(@bar, @foo)
end
def ducktype(duck1, duck2)
p duck1 #=> false
p duck2 #=> false
puts "foo: #{foo} bar: #{bar}" #=> "foo: false bar: false"
duck1 = true if duck2 == false #<= For #duck_foo: I want to make @foo = true if @bar == false. But it only changes duck1 to true. / For #duck_bar: I want to make @bar = true.
p duck1 #=> true
p duck2 #=> false
puts "foo: #{foo} bar: #{bar}" #=> "foo: false bar: false" => @foo is still false. I want it true!
end
end
duck = Duck.new
duck.duck_foo
duck.duck_bar
我希望看到#duck_foo的輸出是@foo變為true。 但是,它僅將duck1更改為true,而@foo仍為false。
我該如何運作?
本質上,我正在嘗試:
def duck_foo
p foo
p bar
puts "foo: #{foo} bar: #{bar}"
@foo = true if @bar == false #=> change @foo to true.
p foo
p bar
puts "foo: #{foo} bar: #{bar}"
end
def duck_bar
p foo
p bar
puts "foo: #{foo} bar: #{bar}"
@bar = true if @foo == false #=> change @bar to true.
p foo
p bar
puts "foo: #{foo} bar: #{bar}"
end
成:
def duck_foo
ducktype(@foo, @bar)
end
def duck_bar
ducktype(@bar, @foo)
end
def ducktype(duck1, duck2)
#whatever code necessary to preserve the original methods' behavior.
end
因此,代碼更干凈,更易於維護。
希望這是有道理的。 感謝大家!
這里的問題是,您試圖通過分配給局部變量引用來修改實例變量所持有的值。 抱歉,但這在ruby中不起作用-分配給局部變量只會使局部變量指向新對象,而不會影響第一個對象。
但是,您可以做一個很小的修改就可以相當簡單地完成所需的工作(盡管您想使用attr_accessor
而不是attr_reader
來避開難看的eval塊):
class Duck
attr_accessor :foo, :bar
def initialize
@foo = false
@bar = false
end
def duck_foo
ducktype(:foo, :bar)
end
def duck_bar
ducktype(:bar, :foo)
end
def ducktype(duck1, duck2)
p send(duck1) #=> false
p send(duck2) #=> false
puts "foo: #{foo} bar: #{bar}" #=> "foo: false bar: false"
send(:"#{duck1}=", true) if send(duck2) == false
p send(duck1) #=> true
p send(duck2) #=> false
puts "foo: #{foo} bar: #{bar}" #=> "foo: true bar: false"
end
end
在此實現中,我們沒有傳遞實例變量(傳遞給局部變量時會丟失上下文),而是將我們的意圖作為符號“消息”傳遞。 然后,我們可以根據需要使用這些符號與我們的對象進行交互。
一種方法是檢查object_id
:
def ducktype(duck1, duck2)
puts "foo: #{foo} bar: #{bar}" #=> "foo: false bar: false"
if duck1.object_id == @foo.object_id
@foo = true if !duck2
elsif duck1.object_id == @bar.object_id
@bar = true if !duck2
end
puts "foo: #{foo} bar: #{bar}" #=> "foo: true bar: false"
end
由於您要傳遞布爾值,因此您無法像在使用Strings一樣使用函數str.replace('true')
在函數內更改其值。
object_id
? 如果@foo
和@bar
是字符串而不是布爾值,則可以執行以下操作:
def ducktype(duck1, duck2)
puts "foo: #{foo} bar: #{bar}" #=> "foo: false bar: false"
duck1.replace('true') if duck2 == 'false'
puts "foo: #{foo} bar: #{bar}" #=> "foo: true bar: false"
end
不管其類型為何, duck1 = true
都不起作用是因為已為其分配了新實例。 即:
duck1 = true # => true
duck1.object_id # => 2
duck1 = false # => false
duck1.object_id # => 0 <-- id changes
duck1 = 'true' # => "true"
duck1.object_id # => 6563940
duck1.replace('false') # => "false"
duck1.object_id # => 6563940 <-- id stays the same
因此,如果數據類型不具有可以更改其自身值的成員函數,則似乎必須像上面那樣通過檢查object_id
來完成此任務。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.