Понимание частных методов в 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
Ответы
Ответ 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)