В Ruby, к какому объекту применяется метод put? - PullRequest
0 голосов
/ 11 января 2019

В ruby ​​вы используете точку для вызова метода или, другими словами, для отправки метода к объекту обработки.

"100".to_i

Отправляем на объект "100" сообщение to_i

Когда мы делаем:

puts "hello"

Метод устанавливает, к какому объекту применяется?

Я думал это:

self.puts "hello"

Где self будет основным, например, среда, в которой вы сейчас находитесь, например, консоль irb.

Но выдает ошибку.

Traceback (most recent call last):
        2: from /Users/albert/.rbenv/versions/2.5.0/bin/irb:11:in `<main>'
        1: from (irb):17
NoMethodError (private method `puts' called for main:Object)

Почему это не так? Где применяется метод применяется?

Ответы [ 3 ]

0 голосов
/ 11 января 2019

ОП правильно считает, что, когда явный получатель опущен, получатель становится self. А поскольку puts работает без явного получателя, неплохо было бы попробовать self.puts "hello" в той же среде. Действительно, puts определено на main, или на любом объекте, на который self указывает в данной среде.

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

Стандартный способ обойти это ограничение - использовать метод send следующим образом:

self.send(:puts, "hello")
0 голосов
/ 11 января 2019

В Ruby, если вы не указали получателя отправленного сообщения, неявным получателем будет всегда self. (Без исключений.)

Итак, говоря

foo

где foo не является локальной переменной в текущей лексической области, всегда эквивалентно

self.foo

Однако есть небольшая складка: в Ruby определение метода private является «методом, который может быть вызван только в результате отправки сообщения без получателя». Таким образом, хотя foo и self.foo эквивалентны с точки зрения получателя отправляемого сообщения, могут существовать различия с контролем доступа. В частности, если foo равно private, то foo будет работать, но self.foo будет raise NoMethodError исключение с сообщением (например) NoMethodError (private method `foo' called for main:Object).

Итак, вы были правы все время:

puts

эквивалентно

self.puts

но вы неправильно прочитали сообщение об ошибке: метод не существует, просто метод private.

В частности, все те методы, которые предназначены для того, чтобы больше походить на «процедуры» в том, что они на самом деле не делают ничего интересного со своим получателем, определены в Kernel и определены как private методы. Сюда также входят такие методы, как Kernel#print, Kernel#require и т. Д.

0 голосов
/ 11 января 2019

puts является модульным методом Kernel. Kernel включено Object, поэтому доступно практически для каждого класса. puts "foo" и Kernel.puts "foo" эквивалентны. Разница в том, что Kernel.puts явная, тогда как puts может вызывать локально определенный метод puts.

def puts(str)
  p "my puts: #{str}"
end

puts "foo";        # "my puts: foo"
Kernel.puts "foo"  # foo

Под капотом Kernel.puts звонит $stdout.puts. $stdout - это предопределенный глобальный экземпляр IO.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...