Вопрос по ruby – Как мне вызвать метод, который является хеш-значением?

2

Ранее я спрашивал об умном способе выполнения метода при заданном условии & quot;Ruby умный способ выполнить функцию по условию. & Quot;

Решения и время отклика были отличными, хотя после внедрения хэш-код лямбда-кода становится довольно уродливым. И я начал экспериментировать.

Следующий код работает:

def a()
  puts "hello world"
end

some_hash = { 0 => a() }

some_hash[0]

Но если я заверну это в классе, он перестанет работать:

class A

  @a = { 0 => a()}

  def a()
    puts "hello world"
  end


  def b()
    @a[0]
  end

end

d = A.new()

d.b()

Я не могу понять, почему он должен перестать работать, кто-нибудь может подсказать, как заставить его работать?

Ваш Ответ

7   ответов
1

и вот как я объяснил это себе на примере:

require 'logger'
log = Logger.new('/var/tmp/log.out')

def callit(severity, msg, myproc)
  myproc.call(sev, msg)
end

lookup_severity = {}
lookup_severity['info'] = Proc.new { |x| log.info(x) }
lookup_severity['debug'] = Proc.new { |x| log.debug(x) }

logit = Proc.new { |x,y| lookup_sev[x].call(y) }

callit('info', "check4", logit)
callit('debug', "check5", logit)
2

почему бы не обернуть все ваши методы в класс так:

# a container to store all your methods you want to use a hash to access
class MethodHash
  alias [] send
  def one
    puts "I'm one"
  end
  def two
    puts "I'm two"
  end
end

x = MethodHash.new
x[:one] # prints "I'm one"
x.two # prints "I'm one"

или, чтобы использовать ваш пример:

# a general purpose object that transforms a hash into calls on methods of some given object
class DelegateHash
  def initialize(target, method_hash)
    @target = target
    @method_hash = method_hash.dup
  end
  def [](k)
    @target.send(@method_hash[k])
  end
end

class A
  def initialize
    @a = DelegateHash.new(self, { 0 => :a })
  end
  def a()
    puts "hello world"
  end
  def b()
    @a[0]
  end
end

x = A.new
x.a #=> prints "hello world"
x.b #=> prints "hello world"

Еще одна основная ошибка, которую вы сделали, это то, что вы инициализировали@a вне любого метода экземпляра - просто голый внутри определенияA, Это большое время нет-нет, потому что это просто не работает. Помните, что в ruby все является объектом, включая классы и@ префикс означает экземпляр переменная любого объекта в настоящее время самостоятельно. Внутри определения метода экземпляра,self это пример класса. Но вне этого, только внутри определения класса,self это объект класса - так вы определили переменная экземпляра с именем@a для объекта классаA, что ни один из случаевA можно добраться напрямую.

У Ruby есть причина для такого поведения (переменные экземпляра класса могут быть очень полезны, если вы знаете, что Вы делаете), но это более продвинутый метод.

Короче говоря, только инициализировать переменные экземпляра вinitialize метод.

1

первая строка в вашем классе вызывает метод, который еще не существует. Однако он даже не будет существовать после загрузки всего класса, поскольку это будет вызов метода класса, а вы только определили методы экземпляра.

Также имейте в виду, что {0 = & gt; a ()} вызовет метод a (), а не создаст ссылку на метод a (). Если вы хотите добавить туда функцию, которая не будет оценена позднее, вам придется использовать какую-то лямбду.

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
5

вы не помещаете лямбду в хеш. Вы ставите результат вызоваa() в текущем контексте.

Учитывая эту информацию, подумайте, что означает код в вашем классе. Контекстом определения класса является класс. Итак, вы определяете метод экземпляра под названиемaи присвойте переменную экземпляра класса хешу, содержащему результат вызоваa в текущем контексте. Текущий контекст - это класс A, а класс A не имеет метода класса, называемогоaТаким образом, вы пытаетесь поместить результат несуществующего метода. Тогда в методе экземпляраbвы пытаетесь получить доступ к переменной экземпляра с именем@a - но это не так.@a определенный в контексте класса принадлежит самому классу, а не любому конкретному экземпляру.

Итак, прежде всего, если вы хотите лямбду, вам нужно сделать лямбду. Во-вторых, вы должны четко понимать разницу между классом и экземпляром этого класса.

Если вы хотите составить список имен методов, которые будут вызываться при определенных условиях, вы можете сделать это следующим образом:

class A
  def self.conditions() { 0 => :a } end

  def a
    puts "Hello!"
  end

  def b(arg)
    send self.class.conditions[arg]
  end
end

Это определяет хэш условий как метод класса (облегчающий доступ к нему), и хеш просто содержит имя вызываемого метода, а не лямбду или что-то подобное. Поэтому, когда вы звонитеb(0), ЭтоsendСамо сообщение, содержащееся в A.conditions [0], котороеa.

3
table = {
  :a => 'test',
  :b => 12,
  :c => lambda { "Hallo" },
  :d => def print(); "Hallo in test"; end
}

puts table[:a]
puts table[:b]
puts table[:c].call
puts table[:d].send( :print )
0

puts string

end

some_hash = { 0 => a }

some_hash[0].call("Hello World")

some_hash[0][]

7

a во время его добавления в хеш, а не при извлечении из хеша (попробуйте в irb).

Это не работает в классе, потому что нетa метод, определенный в классе (вы в конечном итоге определяете методa в случае.

Попробуйте на самом деле использовать лямбды, как

{0 => lambda { puts "hello world" }} 

вместо

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded

Похожие вопросы