2015-12-20 2 views
4

Мое понимание состоит в том, что private означает частное использование экземпляра. Частные методы не могут быть вызваны с явным получателем, даже self. Для того, чтобы позвонить частный метод, я должен пройти через процесс, как показано ниже:Как получить доступ к приватным методам

class Sample 
    def foo 
    baz 
    end 

    private 
    def baz 

    end 
end 

Sample.new.foo 

Это будет вызывать частный baz метод. Есть ли способ прямого вызова частного метода с явным приемником?

+0

Непонятно, что вы подразумеваете под «частным экземпляром». – sawa

+3

В чем смысл сделать метод приватным, если вы хотите позвонить явным получателем? Единственная цель создания частного метода - избежать этого. – sawa

ответ

6

Да, это возможно с Kernel#send:

receiver.send :method_name, parameters 

Хотя есть обходные пути, как BasicObject#instance_eval или Kernel#binding манипуляций, общий способ вызова частного метода является вызов send на ресивере.

+0

Если есть такой способ преодоления частного ограничения, я не понимаю, почему должен быть способ написать метод в частной области. Вы можете мне объяснить? – RAJ

+0

@ RAJ Ruby управляет контрактами, а модификатор 'private' - это контракт, который помешает вам и вашим пользователям случайно вызвать метод стандартным способом с помощью' receiver.method_name'. OTOH, поскольку классы Ruby открыты, и всем по-прежнему разрешено полностью перезаписывать любой метод в любом классе, что не имеет смысла искусственно запрещать вызов частных методов. BTW, даже в Java, можно легко вызвать частные методы, используя отражение. – mudasobwa

+0

Хорошо, так что использовать 'Private' не нужно, кроме как избежать случайного вызова пользователем определенных методов? То, чему меня учили, - это частный, предназначенный только для обеспечения безопасности! (Не для звонка). Если я могу обойти почти любое ограничение доступа, защиту, скрытие и инкапсуляцию, тогда это кажется нелогичным, а? – RAJ

2

Используя BasicObject#instance_eval, вы можете позвонить по частному методу.

class Sample 
    private 
    def baz 
    'baz called' 
    end 
end 

Sample.new.instance_eval('baz') 
# => 'baz called' 
Sample.new.instance_eval { baz } 
# => 'baz called' 
1

Как показано в других ответах, вы можете использовать send для вызова частного метода. Однако это может привести к некоторому нечеткому коду.

Если вам действительно нужен, чтобы ваш метод был общедоступным для экземпляров вашего класса, вы можете просто сбросить видимость метода. Если предположить, что класс не определен в коде, просто открыть его и установить видимость метода:

class Sample 
    public :baz 
end 

Теперь вы можете назвать его:

s = Sample.new 
s.baz 
# => 'baz called' 
1

Есть два уровня, на которых ваш вопрос можно ответить: уровень базового языка и отражающий метауровень.

На уровне базового языка, ответ совершенно очевиден, если вы только контрастируете определение частной жизни с вопросом:

частных методы могут быть вызваны только без явного приемника

и

Можно ли позвонить частному лицу без явного приемника?

Ответ, очевидно, «Нет», два предложения прямо противоречат друг другу.

На рефлексивном метауровне, однако, ответ «Да». Фактически, вы можете делать почти что угодно на метауровне и обходить практически любые ограничения доступа, защиту, скрытие и инкапсуляцию.

Object#send, основной целью которого является, чтобы позволить вам вызвать метод, имя которого вы не знаете, до времени выполнения, а также имеет дополнительный побочный эффект обходя ограничения доступа, как private и protected. (Он также игнорирует уточнения, что является важным ограничением, о котором вы должны знать!)

Смежные вопросы