Подтвердить что ты не робот

Понимание частных методов в Ruby

class Example
 private
 def example_test
  puts 'Hello'
 end
end

e = Example.new
e.example_test

Это, конечно, не сработает, потому что мы указали явный получатель - экземпляр Example (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 на себе)?

Надеюсь, я не слишком смутил его, я все еще добрался до Руби.


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

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

4b9b3361

Ответ 1

Здесь короткий и длинный. Какие частные средства в Ruby - это метод, который нельзя вызывать с явными приемниками, например. some_instance.private_method (значение). Поэтому, хотя неявный получатель сам по себе, в вашем примере вы явно используете 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

Ответ 2

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

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

foo = :bar

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

self.foo = :bar

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

Ответ 3

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

Ответ 4

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

Ответ 5

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

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

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

Ответ 6

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

class Example
 private
 def example_test
  puts 'Hello'
 end
end

e = Example.new
e.send(:example_test)