Ruby作为一种“纯粹的”面向对象的语言---与Ruby的不一致?

时间:2014-02-03 07:59:46

标签: ruby string oop syntax

我经常读到Ruby是一种纯粹的面向对象语言,因为命令通常是作为传递给对象的消息给出的。

例如:

在Ruby中,写一个:"A".ord来获取A0x41.chr的ascii代码,以便在给定ascii代码的情况下发出字符。 这与Python的相反:ord("A")chr(0x41)

到目前为止一直很好--- Ruby的语法是消息传递。

但是在考虑字符串输出命令时会出现明显的不一致:

现在有人:puts strputs(str)而不是str.puts

鉴于Ruby语法的纯对象期望,我希望输出命令是传递给字符串对象的消息,即从字符串类调用方法,因此str.puts

有任何解释吗?我错过了什么吗?

由于

4 个答案:

答案 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(例如,方法不是对象),但在这种情况下,它是。 putsKernel#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那样特别依赖于接收器),而是用于遍布各处的方法。因此,对于像打印这样的方法,至少有三个逻辑选项可以考虑。

  • 在要打印的对象上定义的OOP方法
  • 在应该打印的对象上定义的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