Хорошо, вы неясны.
Локальные переменные в 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
с, proc
с или Proc
с).
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"]