2009-07-01 4 views
2

Раньше я спрашивал о умном способе выполнения метода при заданном условии «Ruby a clever way to execute a function on a condition».Как я могу назвать метод хеш-значением?

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

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

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() 

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

ответ

8

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

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

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

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

вместо

+0

Это действительно то, что я пытался избежать. Код, который я бы поставил в лямбда, может немного запутаться, и у меня будет около 15 элементов хэша. Это немного забивает код. – Peter

+0

@Peter: Является ли код messier в лямбда, чем в методе? – Chuck

+1

, затем передайте имена методов в виде символов и используйте send или Symbol # to_proc. –

1

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

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

+0

Ах, я не понимаю. Ну, так или иначе, чтобы достичь того, что я пытался сделать? – Peter

+0

Вы могли бы сделать что-то вроде этого: @a = {0 => лямбда {A.new.a()}} Тогда вы должны назвать его @a [0] .call –

4

Прежде всего, вы не помещаете лямбда в хэш. Вы ставите результат вызова 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), оно является сообщением, содержащимся в A.conditions [0], которое равно a.

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.

0

а = -> (строка = "строка не прошла") сделать

ставит снабжать струной, тетивой и т.п.

конец

some_hash = {0 => а}

some_hash [0 ] .call («Hello World»)

some_hash [0] []

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) 
1

Я довольно новыми для использования обратных вызовов в Ruby, и это, как я объяснил себе, используя пример:

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)