Estou começando meus estudos no Ruby e me deparei com uma situação curiosa. Vejam o código abaixo:
irb(main):051:0> class MinhaClasse
irb(main):052:1> @valor = 10
irb(main):053:1> def get_valor
irb(main):054:2> @valor
irb(main):055:2> end
irb(main):056:1> end
=> nil
irb(main):057:0> m = MinhaClasse.new
=> #<MinhaClasse:0xc278b5>
irb(main):058:0> m.get_valor
=> nil
Ou seja, tenho uma class com atributo cujo valor é definido em sua declaração. Mas quando tento acessá-lo obtenho nil.
Agora uma alteração na minha classe:
irb(main):061:0> class MinhaClasse
irb(main):062:1> @valor
irb(main):063:1> def initialize(v)
irb(main):064:2> @valor = v
irb(main):065:2> end
irb(main):066:1> def get_valor
irb(main):067:2> @valor
irb(main):068:2> end
irb(main):069:1> end
=> nil
irb(main):070:0> m = MinhaClasse.new(10)
=> #<MinhaClasse:0x1efa490 @valor=10>
irb(main):071:0> m.get_valor
=> 10
Por outro lado:
irb(main):072:0> class MinhaClasse
irb(main):073:1> attr_accessor :valor
irb(main):074:1> end
=> nil
irb(main):075:0> m = MinhaClasse.new
ArgumentError: Wrong # of arguments(0 for 1)
from (irb):75:in `new'
from (irb):75:in `binding'
from C:/jruby-1.0.2/lib/ruby/1.8/irb.rb:150:in `evaluate'
from C:/jruby-1.0.2/lib/ruby/1.8/irb.rb:150:in `eval_input'
from C:/jruby-1.0.2/lib/ruby/1.8/irb.rb:70:in `signal_status'
from C:/jruby-1.0.2/lib/ruby/1.8/irb.rb:147:in `eval_input'
from C:/jruby-1.0.2/lib/ruby/1.8/irb.rb:70:in `each_top_level_statement'
from C:/jruby-1.0.2/lib/ruby/1.8/irb.rb:146:in `loop'
from C:/jruby-1.0.2/lib/ruby/1.8/irb.rb:146:in `catch'
from C:/jruby-1.0.2/lib/ruby/1.8/irb.rb:146:in `eval_input'
from C:/jruby-1.0.2/lib/ruby/1.8/irb.rb:70:in `start'
from C:\jruby-1.0.2\bin\..\bin\jirb_swing:41:in `catch'
from C:/jruby-1.0.2/lib/ruby/1.8/irb.rb:69:in `start'
from C:\jruby-1.0.2\bin\..\bin\jirb_swing:41
irb(main):076:0> m = MinhaClasse.new(10)
=> #<MinhaClasse:0x162f16 @valor=10>
Então a moral da história seria: “Se sua classe possui atributos sempre inicialize-os no construtor. Não adianta inicializá-los na declaração pois eles sempre vão começar com nil.”? :?
Se é assim então por que no primeiro código já não é emitido nenhum tipo de aviso ou exceção? Se existe alguma forma de contornar essa situação, como é?
Vc não pode pensar numa classe ruby como se fosse uma classe java.
Teste isso:
class Z
(1..1000).each { puts "oi" }
end
como esta unica linha de codigo não está dentro de nenhuma definição de método, ela será executada assim que vc declarar a classe
agora veja só
irb(main):052:0> x = class W
irb(main):053:1> @valor=10
irb(main):054:1> end
=> 10
irb(main):055:0> puts x
10
=> nil
interessante, não? então veja
irb(main):056:0> x = class W
irb(main):057:1> @valor = @valor + 5
irb(main):058:1> end
=> 15
irb(main):059:0> x = class W
irb(main):060:1> @valor = @valor + 50
irb(main):061:1> end
=> 65
e não para por ai:
irb(main):063:0> y = class W
irb(main):064:1> @@x = 4
irb(main):065:1> end
=> 4
irb(main):066:0> y = class W
irb(main):067:1> @@x = @@x * 2
irb(main):068:1> end
=> 8
irb(main):069:0> y = class W
irb(main):070:1> z = 90
irb(main):071:1> end
=> 90
irb(main):072:0> y = class W
irb(main):073:1> z = z / 3
irb(main):074:1> end
NoMethodError: undefined method `/' for nil:NilClass
from (irb):73
from ♥:0
Segundo o livro: “variaveis de instância podem ser declaradas dentro de qualquer método da classe, porem se forem declaradas logo após a definição da classe, vc tem uma variável de instância de classe ( :hunf: ), que só pode ser acessada usando um método de classe”.
class Numero
@numero;
def initialize(num=-1)
@numero = num;
end
def get_num
@numero
end
end
numero = Numero.new
puts numero.get_num
numero = Numero.new(3)
puts numero.get_num
output:
-1
3
Porque você nao pode inicializar no construtor nao vejo o problema nisso…
Espero ter respondido a sua duvida…
Não seria uma perguntar em um forum de ruby?
Boa sorte nos estudos… :thumbup:
class X
@numero = 10
def get_numero
@numero
end
def set_numero(valor)
@numero = valor
end
def X.numero
@numero
end
end
O correto:
class X
attr_accessor :numero
@@numero = 20
def initialize
@numero = 10
end
def self.numero
@@numero
end
end
No caso de métodos de classe, ou use o prefixo self. ou faça o seguinte:
class X
class << self
def numero
@@numero
end
end
end
Repitam o mantra: "getters e setters não tem utilidade em Ruby". Usem attr_accessor para a mesma função. Outro mantra: "não criem ambiguidades à toa, existe $, @ e @@ por uma razão".
:shock: Opa! Me explique melhor isso! Através do operador "<<" você adicionou um método à variável class de X chamado numero que retorna uma variável de classe (estática?) que por acaso também se chama numero. É isso?