Vous pouvez penser à blocs que la fermeture à la fois sur l'ensemble des variables locales et la self
actuelle.
Dans Ruby, vous aurez toujours accès aux variables locales, quoi qu'il arrive. Le self
encapsule des méthodes d'instance sur l'objet actuel ainsi que des variables d'instance.
Consultez le code suivant:
class Table
def initialize(legs)
@legs = legs
end
def with_legs
yield @legs
end
end
Et puis:
def some_calling_method
name = "Yehuda"
Table.new(4) {|legs| puts "#{name} gnaws off one of the #{legs} legs" }
end
par la sémantique de blocs de Ruby, vous pouvez être assuré que name
sera disponible à l'intérieur du bloc, même sans regarder la méthode vous appelez.
Cependant, tenez compte des éléments suivants:
class Person
def initialize(name)
@name = name
end
def gnaw
Table.new(4).with_legs do |legs|
puts "#{@name} gnaws off one of the #{legs} legs"
end
end
end
Person.new("Yehuda").gnaw
Dans ce cas, nous accèdent à la variable d'instance @name
à l'intérieur du bloc. Cela fonctionne très bien dans ce cas, mais n'est pas garanti. Et si nous avons mis la table un peu différemment:
class Table
def initialize(legs)
@legs = legs
end
def with_legs(&block)
self.instance_eval(&block)
end
end
En effet, ce que nous disons « évaluer le bloc dans le contexte d'un différent soi ». Dans ce cas, nous évaluons le bloc dans le contexte de la table. Pourquoi ferais-tu ça?
class Leg
attr_accessor :number
def initialize(number)
@number = number
end
end
class Table
def initialize(legs)
@legs = legs
end
def with_leg(&block)
Leg.new(rand(@legs).instance_eval(&block)
end
end
Maintenant, vous pouvez faire:
class Person
def initialize(name)
@name = name
end
def gnaw
Table.new(4).with_leg do
puts "I'm gnawing off one of leg #{number}"
end
end
end
Si vous voulez accéder à l'objet de personne à l'intérieur du bloc, vous auriez à faire:
class Person
def initialize(name)
@name = name
end
def gnaw
my_name = name
Table.new(4).with_leg do
puts "#{my_name} is gnawing off one of leg #{number}"
end
end
end
Comme vous pouvez voyez, l'utilisation de instance_eval peut rendre plus simple et moins encombrant l'accès aux méthodes d'un objet lointain à l'intérieur d'un bloc, mais au prix de rendre le self
inaccessible. La technique est généralement utilisée dans les DSL, où un certain nombre de méthodes sont injectées dans le bloc, mais le soi n'a pas beaucoup d'importance.
C'est ce qui se passe avec Tk; ils utilisent instance_eval pour injecter leur propre self
dans le bloc, ce qui efface votre self
propre.
Merci, Katz. J'ai besoin de temps pour digérer tout ce que tu as dit ... – pierrotlefou