Fuentes Vinícius Baggio - Ruby on Rails: coloque sua aplicação web nos trilhos стр 13.

Шрифт
Фон

plos a seguir.

Primeiramente, vejamos como que funciona o #to_proc:

upcase_it = :upcase.to_proc

upcase_it.call('abcde') # ABCDE

upcase_it.call(123) # NoMethodError: undefined method

# ùpcase' for 123:Fixnum

Ou seja, o proc gerado basicamente chama o método no objeto. Porém, usado

com o &, podemos criar filtros de maneira simples e enxuta:

# Forma tradicional usando bloco

%w{pera uva jaca}.map { |fruit| fruit.upcase }

# ["PERA", "UVA", "JACA"]

# Usando o #to_proc

%w{pera uva jaca}.map(&:upcase)

# ["PERA", "UVA", "JACA"]

47

2.5. Funções, blocos, lambdas e closure

Casa do Código

lambdas

Lambdas são bem parecidos com procs, e muitas vezes são usados de forma in-

tercambiável. A forma de construir lambdas é bastante parecida com procs:

upcase_it = lambda { |x| x.upcase }

upcase_it.call("abc") # ABC

# Arity é o número de parâmetros que o lambda aceita

upcase_it.arity # 1

Porém, lambdas possuem um atalho especial:

upcase_it = ->(x) { x.upcase }

upcase_it.call("abc") # ABC

Não existe uma recomendação para o uso das notações. Porém a primeira é mais

utilizada apenas por razões históricas: a notação ->() é uma introdução recente à

linguagem. Fique à vontade para usar a que você mais gostar.

Diferenças entre procs e lambdas

Apesar de serem parecidos, procs e lambdas não são iguais em dois comporta-

mentos.

Primeiro, vimos anteriormente que variáveis em excesso não causam nenhum

problema com blocos e são simplesmente ignorados, e isso acontece com procs, mas

não com lambdas:

show = proc { |x, y| puts "#{x}, #{y}" }

show.call(1)

# 1,

show.call(1, 2, 3)

# 1, 2

show = ->(x,y) { puts "#{x}, #{y}" }

show.call(1, 2)

# 1, 2

show.call(1)

# ArgumentError: wrong number of arguments (1 for 2)

show.call(1, 2, 3)

# ArgumentError: wrong number of arguments (3 for 2)

A segunda diferença é no uso do return. Dentro de blocos, quando usamos

return, o que de fato é retornado é o método associado, já que blocos/procs não

consideram o return. Em contrapartida, lambdas são mais próximos a métodos e

funções e retornam apenas ao contexto a que pertencem:

48

Casa do Código

Capítulo 2. Conhecendo Ruby

def proc_stop

puts "Cheguei..."

proc { puts "Hey"; return; puts "Ho!" }.call

puts "Saindo..."

end

proc_stop # Cheguei...; Hey

def lambda_stop

puts "Cheguei..."

lambda { puts "Hey"; return; puts "Ho!" }.call

puts "Saindo..."

end

lambda_stop # Cheguei...; Hey; Saindo...

closures

Closure, ou fechamento, é uma característica de funções que podem ser as-

sociadas a variáveis e podem ser invocadas a qualquer momento. Quando funções

com essa característica são criadas, elas carregam em si não apenas o código a ser

executado mas também referências à todas as variáveis existentes naquele escopo.

Em Ruby, lambdas e procs são closures, portanto carregam em si referências às

variáveis em seu escopo. Vejamos um exemplo:

def create_lambda

value = 10

-> { value += 1; puts value }

end

l = create_lambda

l.call # 11

l.call # 12

O que acontece no exemplo anterior é que, quando o lambda é criado, a va-

riável value está em seu escopo e portanto o lambda possui uma referência à value.

Mesmo quando a função create_lambda termina de executar, o lambda l ainda con-

segue acessar a variável value pois ainda possui uma referência. Note o exemplo a

seguir, criando duas lambdas:

49

2.5. Funções, blocos, lambdas e closure

Casa do Código

def create_lambda

value = 10

-> { value += 1; puts value }

end

first_lambda = create_lambda

next_lambda = create_lambda

first_lambda.call # 11

next_lambda.call # 11 - "value" é outra variável neste escopo

first_lambda.call # 12

first_lambda.call # 13

Quando executamos create_lambda pela segunda vez, uma nova variável value

foi criada e associada ao escopo de next_lambda.

Dessa forma, next_lambda e

first_lambda referenciam-se à diferentes value, criadas em momentos diferentes.

Agora vamos modificar um pouco o código. Vamos criar duas lambdas dentro

de um mesmo escopo:

def create_lambdas

value = 10

first = -> { value += 1; puts value }

last = -> { value += 1; puts value }

[first, last]

end

first_lambda, last_lambda = create_lambdas

first_lambda.call # 11

last_lambda.call # 12 - "value" é a mesma variável

first_lambda.call # 13

last_lambda.call # 14

É possível observar no exemplo anterior que ambos first_lambda e

last_lambda carregam o mesmo escopo, ou seja, compartilham a mesma re-

ferência à variável value.

50

Casa do Código

Capítulo 2. Conhecendo Ruby

Dica: cuidado com escopo de closures

Há situações que não é possível saber que momento e nem em que or-

dem que lambdas e procs são executados pois são propagados à outras

partes do código. Dessa forma, compartilhar variáveis via closures pode

resultar em comportamento difícil de prever e bugs bem complicados de

serem encontrados. Por isso, preste bastante atenção nas variáveis sendo

compartilhadas via closures.

2.6

Classes e módulos

Ruby é uma linguagem orientada a objetos, e portanto, não poderia faltar uma sin-

Ваша оценка очень важна

0
Шрифт
Фон

Помогите Вашим друзьям узнать о библиотеке