我经常读到Ruby是一种纯粹的面向对象语言,因为命令通常是作为传递给对象的消息给出的。
例如:
在Ruby中,写一个:"A".ord
来获取A
和0x41.chr
的ascii代码,以便在给定ascii代码的情况下发出字符。
这与Python的相反:ord("A")
和chr(0x41)
到目前为止一直很好--- Ruby的语法是消息传递。
但是在考虑字符串输出命令时会出现明显的不一致:
现在有人:puts str
或puts(str)
而不是str.puts
鉴于Ruby语法的纯对象期望,我希望输出命令是传递给字符串对象的消息,即从字符串类调用方法,因此str.puts
有任何解释吗?我错过了什么吗?
由于
答案 0 :(得分:8)
我原本期望输出命令是传递给字符串对象的消息,即从字符串类调用方法,因此str.puts
这是不正确的期望,让我们从那开始吧。为什么要将字符串告诉puts
本身?它会打印出什么?它对文件,I / O流,套接字以及其他可以打印的地方一无所知(也应该不知道)。
当您说puts str
时,它实际上被视为self.puts str
(隐式接收器)。也就是说,消息被发送到当前对象。
现在,所有对象都包含Kernel
模块。因此,所有对象在其方法列表中都有Kernel#puts。任何对象都可以puts
(包括当前对象,self
)。
正如文件所说,
puts str
被翻译为
$stdout.puts str
也就是说,默认情况下,实现被委托给标准输出(打印到控制台)。如果要打印到文件或套接字,则必须在文件或套接字类的实例上调用puts
。这完全是OO。
答案 1 :(得分:5)
Ruby不是完全 OO(例如,方法不是对象),但在这种情况下,它是。 puts
是Kernel#puts
,是$stdout.puts
的简写。也就是说,您正在调用puts
流的$stdout
方法,并将字符串作为要输出到流的参数传递。所以,当你打电话
puts "foo"
你真的在打电话:
$stdout.puts("foo")
这与OO完全一致。
答案 2 :(得分:2)
puts是一种输出流的方法,例如
$stdout.puts("this", "is", "a", "test")
答案 3 :(得分:0)
将某些内容打印到某处至少涉及两件事:写入内容和写入内容。根据您关注的内容,即使在OOP中也可以有不同的实现。除此之外,Ruby还有一种方法可以使方法看起来更像一个函数(即,不像OOP那样特别依赖于接收器),而是用于遍布各处的方法。因此,对于像打印这样的方法,至少有三个逻辑选项可以考虑。
对于第二个选项,IO#write
就是一个例子;接收者是写作的目的地。
没有显式接收器的puts
实际上是Kernel#puts
,并且两者都不作为参数;这是第三种选择的一个例子;你指出这不是OOP是正确的,但是Matz特别提供了Kernel
模块来做这样的事情:函数式方法。
第一个选择是你期待的;这没什么不对。碰巧没有这种类型的众所周知的方法,但它是由一个开发人员在Ruby核心中提出的,但不幸的是,它没有成功。实际上,我觉得和你一样,在我的个人图书馆中有一些类似Object#intercept
的东西。简化版本是:
class Object
def intercept
tap{|x| p x}
end
end
:foo.intercept # => :foo
如果需要,您可以将p
替换为puts
。