Хорошо, вы неясно.
Локальные переменные в ruby начинаются со строчной буквы (например, foo
, bar
или steve
) и имеют лексическую область действия (например, переменные C
). Они не имеют ничего общего с «экземпляром класса».
Переменные экземпляра в ruby начинаются с сигила @
(например, @foo
, @bar
или @carl
) и находятся в области видимости всякий раз, когда текущее значение self
является объектом, в котором они хранятся.
Если вам нужен метод, который может напрямую обращаться к переменным экземпляра объекта, он называется методом экземпляра. Например, battle_cry
и initialize
являются методами экземпляра:
class Character
def initialize(name)
@name=name
end
def battle_cry
@name.upcase + "!!!"
end
def Character.default
new("Leeroy Jenkins")
end
end
Метод класса, напротив, является методом объекта Class
и не имеет доступа ни к одной из переменных экземпляра этого объекта. В приведенном выше примере default
— это метод класса.
Если вам нужен метод (класса или экземпляра), который инициирует изменение или получает значение из текущей области, ruby использует тип обратного вызова, называемый блоком.
class Character
ATTACKS = [ "Ho!", "Haha!", "Guard!", "Turn!", "Parry!", "Dodge!", "Spin!", "Ha", "THRUST!" ]
def attack
ATTACKS.inject(0) { |dmg, word| dmg + yield(word) }
end
end
person = Character.default
puts person.battle_cry
num_attacks = 0;
damage = person.attack do |saying|
puts saying
num_attacks += 1
rand(3)
end
puts "#{damage} points of damage done in #{num_attacks} attacks"
В приведенном выше примере attack
использует ключевое слово yield
для вызова переданного ему блока. Когда мы вызываем attack
, локальная переменная num_attacks
все еще находится в области видимости блока, в который мы ее передаем (здесь он ограничен do ... end
), поэтому мы можем увеличить ее. attack
может передавать значения в блок, здесь они фиксируются в переменной saying
. Блок также передает значения обратно в метод, которые отображаются как возвращаемое значение yield
.
Слово lambda
в рубине обычно означает ключевое слово lambda
, которое используется для превращения блоков в автономные, функционирующие как объекты (которые сами по себе обычно обозначаются как lambda
s, proc
s или Proc
s).
bounce = lambda { |thing| puts "I'm bouncing a #{thing}" }
bounce["ball"]
bounce["frog"]
Итак, я думаю, вы спрашиваете, можете ли вы передать Proc
вместо Hash
в качестве аргумента метода. И ответ "это зависит". Если метод использует только метод #[]
, тогда да:
class Character
attr_accessor :stats
def set_stats(stats)
@stats = stats
end
end
frank = Character.new("Victor Frankenstein")
frank.set_stats({ :str => 7, :dex => 14, :con => 9, :int => 19, :wis => 7, :cha => 11 })
monster = Character.new("Frankenstein's Monster")
monster.set_stats(lambda do |stat_name|
rand(20)
end)
Однако он может использовать некоторые другие методы, специфичные для Hash
, или вызывать один и тот же ключ несколько раз, что может привести к странным результатам:
monster = Character.new("Frankenstein's Monster")
monster.set_stats(lambda do |stat_name|
rand(20)
end)
monster.stats[:dex] #=> 19
monster.stats[:dex] #=> 1
В этом случае вам может быть лучше кэшировать запросы в промежуточном хэше. Это довольно просто, так как Hash
может иметь блок инициализации. Итак, если мы изменим приведенное выше на:
monster.set_stats(Hash.new do |stats_hash, stat_name|
stats_hash[stat_name] = rand(20)
end)
monster.stats[:dex] #=> 3
monster.stats[:dex] #=> 3
Результаты кэшируются в хеше
Чтобы узнать больше об инициализаторах блоков Hash
, см. ri Hash::new
:
-------------------------------------------------------------- Hash::new
Hash.new => hash
Hash.new(obj) => aHash
Hash.new {|hash, key| block } => aHash
------------------------------------------------------------------------
Returns a new, empty hash. If this hash is subsequently accessed
by a key that doesn't correspond to a hash entry, the value
returned depends on the style of new used to create the hash. In
the first form, the access returns nil. If obj is specified, this
single object will be used for all default values. If a block is
specified, it will be called with the hash object and the key, and
should return the default value. It is the block's responsibility
to store the value in the hash if required.
h = Hash.new("Go Fish")
h["a"] = 100
h["b"] = 200
h["a"] #=> 100
h["c"] #=> "Go Fish"
# The following alters the single default object
h["c"].upcase! #=> "GO FISH"
h["d"] #=> "GO FISH"
h.keys #=> ["a", "b"]
# While this creates a new default object each time
h = Hash.new { |hash, key| hash[key] = "Go Fish: #{key}" }
h["c"] #=> "Go Fish: c"
h["c"].upcase! #=> "GO FISH: C"
h["d"] #=> "Go Fish: d"
h.keys #=> ["c", "d"]
person
rampion
schedule
10.07.2009