的檔案Struct::new有以下片段:
Customer = Struct.new('Customer', :name, :address) do |new_class|
p "The new subclass is #{new_class}"
def greeting
"Hello #{name} at #{address}"
end
end # => Struct::Customer
dave = Customer.new('Dave', '123 Main')
dave # => #<struct Struct::Customer name="Dave", address="123 Main">
dave.greeting # => "Hello Dave at 123 Main"
為什么會greeting成為創建子類的方法?它作為引數傳遞給塊。顯然,它也成為執行塊的背景關系。相似地:
[1,2,5].each { |x|
public
def m1 a
a self
end
}[0].m1 3
給出 4。但與 with 不同Struct,該方法默認是私有的。奇怪的。
uj5u.com熱心網友回復:
為什么 greeting 會成為創建的子類的方法?
簡短的回答是:因為這就是Struct.new作業原理。
為什么會這樣呢?想象一下,如果沒有。greeting將被添加到所有結構中,那會很糟糕。
它作為引數傳遞給塊。
這就是“如何”。“塊”實際上是您定義一個函式并將其傳遞給new. 上面的代碼是...的語法糖
func = Proc.new do |new_class|
p "The new subclass is #{new_class}"
def greeting
"Hello #{name} at #{address}"
end
end
Customer = Struct.new('Customer', :name, :address, &func)
有關更多資訊,請參閱塊、程序和 Lambda 的終極指南。
Struct.new運行 proc,傳入新類的名稱,但它以一種特殊的方式運行它。它運行它,就好像它是類一樣Struct::Customer。它(可能)通過呼叫class_eval運行 proc 來做到這一點,就好像它是在另一個類中定義的一樣。
我們也可以這樣做來演示。
class Foo
# Defined inside the Foo class, farewell is a method of Foo.
def farewell
"goodbye"
end
end
# This proc is defined outside the Foo class...
func = Proc.new do
def greeting
"hello"
end
end
# ...but we can run it as if it were.
Foo.class_exec(&func)
dave = Foo.new
p dave.greeting
許多 Ruby 庫都使用這個技巧,并且喜歡它。
傳遞給的塊each也是一個程序,但each只是正常運行它并傳入 Enumerable 的每個元素。
但是,您寫的內容很奇怪。這個...
[1,2,5].each { |x|
public
def m1 a
a self
end
}[0].m1 3
真的是這個。
nums = [1,2,5].each { |x|
def m1(a)
a self
end
}
nums[0].m1(3)
這是真的。
[1,2,5].each { |x|
def m1(a)
a self
end
}
1.m1(3)
each回傳它迭代的內容,所以它回傳[1,2,5]. nums[0]是 1。所以我們呼叫m1的是一個整數。為什么要m1在整數上定義?
不是!它實際上定義在Object. 為什么?
在 Ruby 中,一切都是物件,總是必須有一個self. 當在 Ruby 中的一個類之外時,selfis mainwhich 是一個Object. m1是一種方法Object。
p self # main
p self.class # Object
Integer繼承自Object所以它可以呼叫m1. 我們可以使用method. 一切都是物件,包括Method。
p self.method(:m1) #<Method: Object#m1>
p 1.method(:m1) #<Method: Integer(Object)#m1>
也就是說 m1 是在 Object 上定義的,而 Integer 從 Object 繼承它。
定義m1是each一個紅鯡魚。each只是運行代碼但沒有做任何特別的事情。您可以在main(即物件)中定義它并獲得相同的效果。
def m1(a)
p a self
end
p self.method(:m1)
p 1.method(:m1)
uj5u.com熱心網友回復:
運行這個程式,它會列印出你的問題的答案:
puts "A: self is #{self} so methods defined here get added to #{self}"
Customer = Struct.new('Customer', :name, :address) do |new_class|
puts "B: self is #{self} so methods defined here get added to #{self}"
end
[1].each do |x|
puts "C: self is #{self} so methods defined here get added to #{self}"
end
另外,在您的示例中,請注意greeting未將其作為引數傳遞給塊。事實上,該塊包含定義該greeting方法的代碼,并且在該塊運行之前,該方法不存在。
的源代碼是Struct.new用 C 撰寫的,因此很難說出它到底做了什么,但它可能會self_changer在下面的代碼中執行類似的操作,以便使用不同的 執行給定的塊self:
def self_changer(&proc)
some_object = "abcd"
some_object.instance_eval(&proc)
end
self_changer do
puts "self is #{self}"
end
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/498150.html
