Многие объяснения уже присутствуют, чтобы объяснить, как это происходит и как это исправить, но вы также должны следовать рекомендациям, чтобы избежать NullPointerException
вообще.
См. также: A хороший список лучших практик
Я бы добавил, очень важно, хорошо использовать модификатор final
. Использование "окончательной" модификатор, когда это применимо в Java
Сводка:
final
для обеспечения хорошей инициализации. @NotNull
и @Nullable
if("knownObject".equals(unknownObject)
valueOf()
поверх toString (). StringUtils
StringUtils.isEmpty(null)
. Можно использовать средства доступа атрибута:
class Array
attr_accessor :var
end
Теперь можно получить доступ к нему через:
array = []
array.var = 123
puts array.var
<час> Примечание, которое можно также использовать attr_reader
или attr_writer
для определения просто методов get или методы set или Вы могут определить их вручную как таковой:
class Array
attr_reader :getter_only_method
attr_writer :setter_only_method
# Manual definitions equivalent to using attr_reader/writer/accessor
def var
@var
end
def var=(value)
@var = value
end
end
<час> можно также использовать одноэлементные методы, если Вы просто хотите определенный на единственном экземпляре:
array = []
def array.var
@var
end
def array.var=(value)
@var = value
end
array.var = 123
puts array.var
<час> к вашему сведению, в ответ на комментарий к этому ответу, одноэлементный метод хорошо работает, и следующее является доказательством:
irb(main):001:0> class A
irb(main):002:1> attr_accessor :b
irb(main):003:1> end
=> nil
irb(main):004:0> a = A.new
=> #<A:0x7fbb4b0efe58>
irb(main):005:0> a.b = 1
=> 1
irb(main):006:0> a.b
=> 1
irb(main):007:0> def a.setit=(value)
irb(main):008:1> @b = value
irb(main):009:1> end
=> nil
irb(main):010:0> a.setit = 2
=> 2
irb(main):011:0> a.b
=> 2
irb(main):012:0>
, Как Вы видите, одноэлементный метод setit
установит то же поле, @b
, как тот определил использование attr_accessor..., таким образом, одноэлементный метод является совершенно допустимым подходом к этому вопросу.
Ruby предоставляет методы для этого, instance_variable_get
и instance_variable_set
. ( документы )
можно создать и присвоить новые переменные экземпляра как это:
>> foo = Object.new
=> #<Object:0x2aaaaaacc400>
>> foo.instance_variable_set(:@bar, "baz")
=> "baz"
>> foo.inspect
=> #<Object:0x2aaaaaacc400 @bar=\"baz\">
, Если Ваше использование "класса MyObject" является использованием открытого класса, то, обратите внимание переопределение инициализировать метода.
В Ruby, нет такой вещи как перегрузка... только переопределения или переопределения..., другими словами, может только быть 1 экземпляр любого данного метода, поэтому при переопределении его это переопределено..., и инициализировать метод не отличается (даже при том, что это что новый метод использования Объектов класса).
Таким образом, никогда не переопределяйте существующий метод, не искажая его сначала..., по крайней мере, если Вы хотите получить доступ к исходному определению. И переопределение инициализировать метод неизвестного класса может быть довольно опасным.
Во всяком случае, я думаю, что у меня есть много простого решения для Вас, которое использует фактический метакласс для определения одноэлементных методов:
m = MyObject.new
metaclass = class << m; self; end
metaclass.send :attr_accessor, :first, :second
m.first = "first"
m.second = "second"
puts m.first, m.second
можно использовать обоих метакласс и открыть классы, чтобы стать еще более хитрыми и сделать что-то как:
class MyObject
def metaclass
class << self
self
end
end
def define_attributes(hash)
hash.each_pair { |key, value|
metaclass.send :attr_accessor, key
send "#{key}=".to_sym, value
}
end
end
m = MyObject.new
m.define_attributes({ :first => "first", :second => "second" })
Вышеупомянутое в основном представляет метакласс с помощью метода "метакласса", затем с помощью него в define_ атрибуты для динамичного определения набора атрибутов с attr_ средство доступа и затем вызов метода set атрибута впоследствии с присваиваемым значением в хеше.
С Ruby можно стать творческими и сделать то же самое много различных путей;-)
<час>к вашему сведению, в случае, если Вы не знали, с помощью метакласса, поскольку я сделал средства, Вы только действуете на приведенный пример объекта. Таким образом, вызов define_ атрибуты только определят те атрибуты для того конкретного экземпляра.
Пример:
m1 = MyObject.new
m2 = MyObject.new
m1.define_attributes({:a => 123, :b => 321})
m2.define_attributes({:c => "abc", :d => "zxy"})
puts m1.a, m1.b, m2.c, m2.d # this will work
m1.c = 5 # this will fail because c= is not defined on m1!
m2.a = 5 # this will fail because a= is not defined on m2!
ответ Mike Stone является уже довольно всесторонним, но я хотел бы добавить немного детали.
можно изменить класс в любой момент, даже после того, как некоторый экземпляр был создан и получает результаты, которых Вы требуете. Можно испытать его в консоли:
s1 = 'string 1'
s2 = 'string 2'
class String
attr_accessor :my_var
end
s1.my_var = 'comment #1'
s2.my_var = 'comment 2'
puts s1.my_var, s2.my_var
Другие решения будут работать отлично также, но здесь являются примером с помощью define_ метод, если Вы одержимы не использованием открытых классов..., оно определит переменную "var" для класса массива..., но отметит, что это ЭКВИВАЛЕНТНО использованию открытого класса..., преимущество - Вы, может сделать это для неизвестного класса (так класс любого объекта, вместо того, чтобы открыть определенный класс)... также define_ метод будет работать в методе, тогда как Вы не можете открыть класс в рамках метода.
array = []
array.class.send(:define_method, :var) { @var }
array.class.send(:define_method, :var=) { |value| @var = value }
И вот пример, он - использование... отмечают, что array2, ОТЛИЧАЮЩИЙСЯ массив также имеет методы, поэтому если это не то, что Вы хотите, Вы, вероятно, хотите одноэлементные методы, которые я объяснил в другом сообщении.
irb(main):001:0> array = []
=> []
irb(main):002:0> array.class.send(:define_method, :var) { @var }
=> #<Proc:0x00007f289ccb62b0@(irb):2>
irb(main):003:0> array.class.send(:define_method, :var=) { |value| @var = value }
=> #<Proc:0x00007f289cc9fa88@(irb):3>
irb(main):004:0> array.var = 123
=> 123
irb(main):005:0> array.var
=> 123
irb(main):006:0> array2 = []
=> []
irb(main):007:0> array2.var = 321
=> 321
irb(main):008:0> array2.var
=> 321
irb(main):009:0> array.var
=> 123
Только для чтения, в ответ на Ваше редактирование:
Редактирование: похоже, что я должен разъяснить, что ищу решение для метапрограммирования, которое позволяет мне изменять экземпляр класса во времени выполнения вместо того, чтобы изменить исходный код, который первоначально определил класс. Несколько решений объясняют, как объявить переменные экземпляра в определениях классов, но это не то, о чем я спрашиваю. Извините за беспорядок.
я думаю, что Вы не вполне понимаете понятия "открытых классов", что означает, что можно открыть класс в любое время. Например:
class A
def hello
print "hello "
end
end
class A
def world
puts "world!"
end
end
a = A.new
a.hello
a.world
Вышеупомянутое является совершенно допустимым кодом Ruby, и эти 2 определения классов могут быть распространены через несколько файлов Ruby. Вы могли использовать "define_method" метод в объекте Модуля определить новый метод на экземпляре класса, но это эквивалентно использованию открытых классов.
"Открытые классы" в Ruby означает, что можно переопределить ЛЮБОЙ класс в ЛЮБОМ моменте времени..., что означает, добавляют новые методы, переопределяют существующие методы, или независимо от того, что Вы хотите действительно. Это кажется, что "открытый класс" решение действительно - то, что Вы ищете...