2

以前、特定の条件でメソッドを実行するための賢い方法について質問しました。「Rubyは、条件で関数を実行するための賢い方法です。」

ソリューションと応答時間は素晴らしかったですが、実装すると、ラムダのハッシュを持つことは非常にすぐに醜くなります。それで私は実験を始めました。

次のコードが機能します。

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

なぜ動作を停止する必要があるのか​​わかりませんが、動作させる方法を誰かが提案できますか?

4

7 に答える 7

7

そのコードは機能しません。aハッシュから取得されたときではなく、ハッシュに追加されたときに実行されます(irbで試してください)。

クラスにメソッドが定義されていないため、クラスでは機能しません(最終的にはインスタンスaにメソッドを定義します)。a

次のようなラムダを実際に使用してみてください

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

代わりは

于 2009-07-01T22:13:53.823 に答える
5

まず第一に、あなたはラムダをハッシュに入れていません。呼び出しの結果をa()現在のコンテキストに入れています。

この情報を前提として、クラスのコードの意味を検討してください。クラス定義のコンテキストはクラスです。したがって、と呼ばれるインスタンスメソッドを定義し、現在のコンテキストaでの呼び出しの結果を含むハッシュにクラスインスタンス変数を割り当てます。a現在のコンテキストはクラスAであり、クラスAにはと呼ばれるクラスメソッドがないaため、存在しないメソッドの結果をそこに配置しようとしています。次に、instanceメソッドbで、-というインスタンス変数にアクセスしようとします@aが、1つはありません。クラスコンテキストで定義された@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

于 2009-07-01T22:20:05.620 に答える
3

本当にこの種のものをきれいにしたいだけなら、次のようなクラスですべてのメソッドをラップしてみませんか?

# 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。それはうまくいかないので、これは大したことではありません。ルビーでは、クラスを含むすべてがオブジェクトであり、@プレフィックスは、現在自己であるオブジェクトのインスタンス変数を意味することを忘れないでください。インスタンスメソッド定義内にselfは、クラスのインスタンスがあります。しかし、その外側、クラス定義のすぐ内側にクラスオブジェクトがあります。そのため、クラスオブジェクトにちなんでself名付けられたインスタンス変数を定義しました。これは、のどのインスタンスも直接取得できません。@aAA

Rubyにはこの振る舞いの理由があります(何をしているのかを知っていれば、クラスインスタンス変数は本当に便利です)が、これはより高度な手法です。

つまり、initializeメソッドのインスタンス変数のみを初期化します。

于 2009-07-02T07:48:12.763 に答える
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 )
于 2012-06-20T03:29:52.403 に答える
1

クラスの最初の行は、まだ存在していないメソッドを呼び出しています。ただし、クラス全体がロードされた後でも存在しません。これは、クラスメソッドの呼び出しであり、インスタンスメソッドのみを定義しているためです。

また、{0 => a()}はメソッドa()を呼び出し、メソッドa()への参照を作成しないことにも注意してください。後で評価されない関数をそこに配置したい場合は、ある種のLambdaを使用する必要があります。

于 2009-07-01T22:11:01.300 に答える
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)
于 2012-08-22T10:06:48.263 に答える
0

a =->(string = "文字列が渡されません")do

文字列を入れます

終わり

some_hash = {0 =>a}

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

some_hash [0] []

于 2010-10-25T21:34:59.410 に答える