Доступ к защищенным методам в Ruby
Я пытаюсь отработать наши для себя модификаторы доступа в Ruby. Я имею:
class Person
def initialize (first_name, last_name, age)
@first_name=first_name
@last_name=last_name
@age=age
end
def show()
puts @first_name
puts @last_name
puts @age
end
protected
def compare(other)
self.instance_variable_get(:@age)<=>other.instance_variable_get(:@age)
end
end
p1=Person.new("Some", "Body", "99")
p1.show
puts "\n"
p2=Person.new("Who", "Ever", "21")
p2.show
puts "\n"
p1.compare(p2)
Я получаю сообщение об ошибке "Защищенный метод` Compare'вызван для # (NoMethodError)"Я попытался вызвать изнутри класса и без него. Я вставил без версии здесь. Я думал, что защищенные методы можно вызывать для других объектов того же класса. Что означает эта ошибка, и как мне правильно использовать защищенный метод здесь? Спасибо за помощь.
2 ответа
Вы неправильно поняли protected
видимость. Рубиновый доктор говорит:
Вторая видимость защищена. При вызове защищенного метода отправитель должен быть подклассом получателя, или получатель должен быть подклассом отправителя. В противном случае будет сгенерировано NoMethodError.
Таким образом, ограничение видимости применяется к отправителю, а не к получателю, как вы думали.
Если вы хотите позвонить compare
вне методов экземпляра вам нужно использовать публичную видимость. Вы должны удалить protected
модификатор, если вы можете. Это рекомендуемый способ.
Если код исправлен и вы не можете изменить этот фрагмент кода, вы можете использовать Object#send
метод. Object#send
обойдет ограничение видимости и сможет получить доступ даже к закрытым методам.
p1.send(:compare, p2)
Или вы можете снова открыть класс и изменить видимость compare
учебный класс:
# you code here
# reopen and modify visibility
class Person
public :compare
end
p1.compare(p2)
Вы можете вызвать защищенный метод в публичном методе класса...
class Person
def initialize (first_name, last_name, age)
@first_name=first_name
@last_name=last_name
@age=age
end
def same_age?(other)
age == other.age
end
def show
puts @first_name
puts @last_name
puts @age
end
protected
def age
@age
end
end
p1=Person.new("Some", "Body", "99")
p1.show
puts "\n"
p2=Person.new("Who", "Ever", "21")
p2.show
puts "\n"
# calls a method that calls a protected method
p1.same_age?(p2)
=> false
# but you can't call #age directly...
begin
p1.age
rescue NoMethodError
puts "no method error (protected)"
end