Понимание приватных методов в Ruby

class Example
 private
 def example_test
  puts 'Hello'
 end
end

e = Example.new
e.example_test

Это, конечно, не сработает, потому что мы указали явный получатель - экземпляр примера (e), а это противоречит "приватному правилу".

Но я не могу понять, почему в Ruby нельзя сделать так:

class Foo
 def public_m
  self.private_m # <=
 end
 private
 def private_m
  puts 'Hello'
 end
end

Foo.new.public_m

Текущий объект внутри определения метода public_m (то есть self) является экземпляром Foo. Так почему не разрешено? Чтобы исправить это, я должен изменить self.private_m только на private_m. Но почему это отличается, разве self не является экземпляром Foo внутри public_m? И кто является получателем голого слова private_m звонка? Разве это не self - то, что на самом деле вы опускаете, потому что Ruby сделает это за вас (вызовет private_m для себя)?

Надеюсь, я не слишком запутался, я все еще новичок в Ruby.


РЕДАКТИРОВАТЬ: Спасибо за все ответы. Собрав их все вместе, я смог (наконец-то) понять очевидное (и не столь очевидное для тех, кто никогда не видел таких вещей, как Ruby): что self сам по себе может быть явным и неявным получателем, и это имеет значение. Таким образом, есть два правила, если вы хотите вызвать закрытый метод: self должен быть неявным получателем, и это self должно быть экземпляром текущего класса (в этом случае Example - и это имеет место только тогда, когда self if находится внутри определения метода экземпляра, во время выполнения этого метода). Пожалуйста, поправьте меня, если я ошибаюсь.

class Example 

 # self as an explicit receiver (will throw an error)
 def explicit 
  self.some_private_method
 end

 # self as an implicit receiver (will be ok)
 def implicit
  some_private_method
 end

 private

 def some_private_method; end
end

Example.new.implicit

Сообщение для всех, кто смог найти этот вопрос во время поиска в Google: это может быть полезно — http://weblog.jamisbuck.org/2007/2/23/method-visibility-in-ruby


person Ernest    schedule 27.11.2010    source источник
comment
Здесь Очень похожий вопрос.   -  person demas    schedule 27.11.2010


Ответы (7)


Вот краткое и длинное из этого. Что private означает в Ruby, так это то, что метод нельзя вызывать с явными приемниками, например. some_instance.private_method(значение). Таким образом, несмотря на то, что неявный приемник является self, в вашем примере вы явно используете self, поэтому частные методы недоступны.

Подумайте об этом так: ожидаете ли вы, что сможете вызывать закрытый метод, используя переменную, которую вы присвоили экземпляру класса? Нет. Self — это переменная, поэтому она должна подчиняться тем же правилам. Однако, когда вы просто вызываете метод внутри экземпляра, он работает так, как ожидалось, потому что вы явно не объявляете получателя.

В Ruby вы можете вызывать приватные методы с помощью instance_eval:

class Foo
  private
  def bar(value)
    puts "value = #{value}"
  end
end

f = Foo.new
begin
  f.bar("This won't work")
rescue Exception=>e
  puts "That didn't work: #{e}"
end
f.instance_eval{ bar("But this does") }

Надеюсь, это немного яснее.

-- редактировать --

Я предполагаю, что вы знали, что это сработает:

class Foo
 def public_m
  private_m # Removed self.
 end
 private
 def private_m
  puts 'Hello'
 end
end

Foo.new.public_m
person Community    schedule 27.11.2010
comment
Ну, я думаю, что теперь я это понимаю (или - я намного ближе к этому пониманию :) - person Ernest; 27.11.2010
comment
Поскольку вы цитируете Раздел 512, я надеюсь, вы знаете, что в соответствии с тем же подразделом, который разрешает уведомления о нарушении, такое уведомление должно быть доставлено назначенному агенту для рассматриваемого бизнеса. Насколько мне известно, редактирование ответа на Stack Overflow не является средством правовой защиты, предусмотренным законом. Stack Overflow включает полезное руководство и полную контактную информацию на своей юридической странице. (Примечание CYA: этот комментарий носит импровизированный характер, имеет исключительно информативное значение и не должен рассматриваться как юридическая консультация.) - person Chuck; 06.02.2011

Определение private в Ruby: "можно вызывать только без явного получателя". И именно поэтому вы можете вызывать только частные методы без явного получателя. Другого объяснения нет.

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

foo = :bar

Итак, что вы делаете, если хотите позвонить писателю по имени foo=? Итак, вы должны добавить явный приемник, потому что без приемника Ruby просто не узнает, что вы хотите вызвать метод foo= вместо присваивания значения локальной переменной foo:

self.foo = :bar

Но что делать, если вы хотите назвать private писателя по имени foo=? Вы не можете написать self.foo =, потому что foo= равно private и, следовательно, не может быть вызвано с явным получателем. Что ж, на самом деле для этого конкретного случая (и этого случая только) вы можете использовать явный получатель self для вызова модуля записи private.

person Jörg W Mittag    schedule 27.11.2010
comment
Сотрите первые два предложения, и вы получите отличный ответ. Вы должны были начать с того, что определение private в Ruby может быть вызвано только без явного получателя. И именно поэтому вы можете вызывать только частные методы без явного получателя. Другого объяснения нет. - person ; 28.11.2010
comment
Хороший ответ. Если вам когда-нибудь будет скучно, подумайте об этом: self.foo ||= bar - person Adam Milligan; 28.11.2010
comment
Спасибо, что упомянули об исключении для писателей. +1, даже если я не чувствую себя комфортно с ответом, начнем с того, что так оно и есть... С уважением. - person Ernest; 28.11.2010
comment
Я попытался погуглить рубиновый форум, чтобы узнать, есть ли объяснение почему, предпочтительно от The Matz. Я не мог найти ни одного. Может быть, кто-то с лучшим google-fu мог бы найти его. - person Andrew Grimm; 29.11.2010
comment
Как вы упомянули, первые два предложения не очень помогли ответить на вопрос. Я только что удалил их, так что если кому-то интересно, о чем комментарии: их больше нет. - person Florian Pilz; 13.08.2013
comment
Хорошо, на данный момент Руби просто тупой. Дано: (1) Что ж, на самом деле для этого конкретного случая (и только для этого случая) вы можете использовать явный получатель self для вызова частного писателя, (2) Self — это переменная, поэтому она имеет [?, а не только по определению] следовать тем же правилам. Просто изменить определение. (3) Если self.foo ||= bar работает, то он также может получить доступ к приватному читателю. - person karmakaze; 08.05.2020

Это странно, но многие вещи в модификаторах видимости Ruby странные. Даже если self является неявным получателем, его фактическое указание делает его явным в глазах среды выполнения Ruby. Когда говорится, что приватные методы нельзя вызывать с явным получателем, это и означает, даже self считается.

person Theo    schedule 27.11.2010

IIRC, частные методы допускают только неявный получатель (который, конечно, всегда является самим собой).

person Victor Deryagin    schedule 27.11.2010

Извините за мой предыдущий ответ. Я просто не понимаю вашего вопроса.

Я изменил ваш код следующим образом:

class Foo
 def public_m
  private_m # <=
 end

 def Foo.static_m
   puts "static"
 end

 def self.static2_m
   puts "static 2"
 end

 private 
 def private_m
  puts 'Hello'
 end
end

Foo.new.public_m
Foo.static_m
Foo.static2_m

Вот вызов метода экземпляра:

 def public_m
  private_m # <=
 end

Вот вызов методов класса:

 def Foo.static_m
   puts "static"
 end

 def self.static2_m
   puts "static 2"
 end

Foo.static_m
Foo.static2_m
person demas    schedule 27.11.2010
comment
Я думаю, вы упускаете суть. Насколько я понимаю его вопрос, он не понимает, почему использование self.private_m не работает. Я предполагаю, что он привык к языкам, которые позволяют вам использовать self или this для вызова методов экземпляра или использования переменных экземпляра. Я думаю, что он сбит с толку тем, почему использование Self скрывает работу, а не тем, как работают частные и общедоступные методы доступа. - person ; 27.11.2010
comment
вместо того, чтобы создавать несколько ответов, отредактируйте или дополните свой предыдущий ответ. Это помогает нам держать вещи в контексте. Спасибо. - person the Tin Man; 28.11.2010

Добавление некоторых улучшений в решение User Gates. Вызов частного метода для метода класса или метода экземпляра вполне возможен. Вот фрагменты кода. Но не рекомендуется.

Метод класса

class Example
  def public_m
    Example.new.send(:private_m)
  end

  private
  def private_m
    puts 'Hello'
  end
end

e = Example.new.public_m

Метод экземпляра

class Example
  def self.public_m
    Example.new.send(:private_m)
  end

  private
  def private_m
    puts 'Hello'
  end
end

e = Example.public_m
person Dinesh Pallapa    schedule 09.02.2018

Не совсем отвечает на вопрос, но вы можете вызывать частные методы таким образом

class Example
 private
 def example_test
  puts 'Hello'
 end
end

e = Example.new
e.send(:example_test)
person gates    schedule 27.02.2017