Domanda

def foo
  f = Proc.new { return "return from foo from inside proc" }
  f.call # control leaves foo here
  return "return from foo" 
end

def bar
  b = Proc.new { "return from bar from inside proc" }
  b.call # control leaves bar here
  return "return from bar" 
end

puts foo # prints "return from foo from inside proc" 
puts bar # prints "return from bar" 

Ho pensato che la parola chiave return fosse facoltativa in Ruby e che tu sia sempre return se lo richiedi o meno. Detto questo, trovo sorprendente che foo e bar abbiano un output diverso determinato dal fatto che foo contiene un return in Proc f .

Qualcuno sa perché questo è il caso?

È stato utile?

Soluzione

Ruby ha tre costrutti:

  1. Un blocco non è un oggetto ed è creato da { ... } o do .. . end .
  2. Un proc è un oggetto Proc creato da Proc.new o proc .
  3. Un lambda è un Proc creato da lambda (o proc in Ruby 1.8).

Ruby ha tre parole chiave che ritornano da qualcosa:

  1. return termina il metodo o lambda in cui si trova.
  2. next termina il blocco, proc o lambda in cui si trova.
  3. break termina il metodo che ha ceduto al blocco o invocato il proc o lambda in cui si trova.

In lambdas, return si comporta come next , per qualsiasi motivo. next e break sono chiamati così come sono perché sono più comunemente usati con metodi come ciascuno , dove terminare il blocco causerà l'iterazione riprendi con l'elemento successivo della raccolta e terminando ciascuno ti farà interrompere fuori dal ciclo.


Se usi return all'interno della definizione di foo , tornerai da foo , anche se si trova all'interno di un blocco o di un proc. Per tornare da un blocco, puoi usare invece la parola chiave next .

def foo
  f = Proc.new { next "return from foo from inside proc" }
  f.call # control leaves foo here
  return "return from foo" 
end
puts foo # prints "return from foo"

Altri suggerimenti

Questa è la semantica per Proc ; non è necessariamente la semantica per tutti i blocchi. Sono d'accordo che sia un po 'confuso. È lì per una maggiore flessibilità (e forse in parte perché Ruby non ha specifiche tranne la sua implementazione).

Il comportamento è definito nell'implementazione Proc . I Lambda si comportano diversamente, quindi se desideri che il return s non esca dal metodo allegato, usa lambdas . In alternativa, ometti la parola chiave return dal tuo Proc .

Un'indagine approfondita sulle chiusure di Rubys è qui . È una fantastica esposizione & # 233 ;.

Quindi:

def foo   
  f = Proc.new {
    p2 = Proc.new { return "inner proc"};
    p2.call
    return "proc"
  }
  f.call
  return "foo"
end

def foo2
  result = Proc.new{"proc"}.call
  "foo2 (proc result is: #{result})"
end

def bar
  l = lambda { return "lambda" }
  result = l.call
  return "bar (lambda result is: #{result})"
end

puts foo
# inner proc
puts foo2
# foo (proc result is: proc) 
puts bar
# bar (lambda result is: lambda) 

Pensaci in questo modo: Proc.new crea semplicemente un blocco di codice che fa parte della funzione chiamante. proc / lambda crea una funzione anonima con collegamenti speciali. Alcuni esempi di codice aiuteranno:

def foo
  f = Proc.new { return "return from foo from inside Proc.new" }
  f.call # control leaves foo here
  return "return from foo" 
end

è equivalente a

def foo
  begin
    return "return from foo from inside begin/end" }
  end

  return "return from foo" 
end

quindi è chiaro che il ritorno tornerà dalla funzione 'pippo'

al contrario:

def foo
  f = proc { return "return from foo from inside proc" }
  f.call # control stasy in foo here
  return "return from foo" 
end

equivale a (ignorando i binding poiché non utilizzati in questo esempio):

def unonymous_proc
  return "return from foo from inside proc"
end

def foo
  unonymous_proc()
  return "return from foo" 
end

Il che è chiaramente non tornerà da foo e continuerà invece alla prossima dichiarazione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top