命名空间模块方法定义
Namespacing module method definition
无意间在Ruby的Postgresql gem中看到了这段代码:
### Convenience alias for PG::Connection.new.
def self::connect( *args )
return PG::Connection.new( *args )
end
我玩了一下,发现这个东西就像普通模块 class 方法一样使用(它的调用方式是这样的:PG.connect
)。事实上,我们可以改为 def self.connect ( #args ) ... end
,它的工作原理是一样的。
因为 self::whatever
对我来说是第一次,所以我想知道 self
命名空间在这种情况下到底是做什么的,在这种情况下它的真正目的是什么。任何人都可以帮助阐明这一点吗?
::
是范围解析运算符。所以 self::connect
从 self 解析 connect
。这意味着它相当于 self.connect
。你可以从这个非常人为的例子中看到它是如何工作的:
class Foo; end
class Bar
def Foo::baz
"Hello World"
end
end
puts Foo.baz # "Hello World"
当然我们也可以只使用def Foo.baz
得到完全相同的结果。
Ruby Style guide 不鼓励使用双冒号定义方法:
Do not use :: to define class methods.
# bad
class Foo
def self::some_method
end
end
# good
class Foo
def self.some_method
end
end
除了引用常量和构造函数之外,也不推荐用于其他用途:
Use :: only to reference constants (this includes classes and modules)
and constructors (like Array() or Nokogiri::HTML()). Do not use :: for
regular method invocation.
在某些情况下,::
在某种程度上等同于 .
。 (我将省略一个精确的定义,在哪些 exact 情况下它是等价的,以及等价到什么程度,因为我承认我自己并不完全了解它,也没有很好的记录。 )
这是 ::
和 .
行为不同的示例:
module Foo
def self.Bar
'method'
end
Bar = 'constant'
def self.Qux; end
end
Foo.Bar
#=> 'method'
Foo::Bar
#=> 'constant'
Foo::Bar()
#=> 'method'
Foo.Qux
Foo::Qux
# NameError (uninitialized constant Foo::Qux)
Foo::Qux()
[注意:这不是一个完美的例子,因为这是关于消息发送方面的事情,而你的例子是关于事情的方法定义方面的。我相信在方法定义方面,它们是 100% 相同的,因为 def
从不定义常量,因此没有歧义。]
所有风格指南都强烈反对这种用法,从强烈建议反对它的消息感知部分到完全禁止这两种用法。这样做的主要原因是两者在消息发送方面的行为不同,这可能会导致混淆。当不对两者使用相同的运算符时,解释方法查找(动态,在继承链中向上)和常量查找(首先是静态,词法向外,然后是动态,在继承链中向上)之间的概念差异也更简单。
许多 Rubyists 使用的典型风格是:
- 永远不要使用
::
作为单例方法定义,总是使用 .
.
- 始终使用
::
在文档中引用单例方法,永远不要使用 .
。
- 始终使用
.
作为文档中消息发送(包括单例方法)的用法示例,永远不要使用 ::
。
- 永远不要使用
::
发送消息(包括单例方法),始终使用 .
.
最后两个有时会软化以允许应该 return 模块或 类 的方法,并允许充当工厂的方法(例如 Nokogiri::XML
)通过消息调用发送 "look like" 常量查找,(例如 Nokogiri::XML('<root/>')
而不是 Nokogiri.XML('<root/>')
)。
有一个 feature request for removing this usage of ::
, but it was rejected 主要是因为向后兼容性问题。
无意间在Ruby的Postgresql gem中看到了这段代码:
### Convenience alias for PG::Connection.new.
def self::connect( *args )
return PG::Connection.new( *args )
end
我玩了一下,发现这个东西就像普通模块 class 方法一样使用(它的调用方式是这样的:PG.connect
)。事实上,我们可以改为 def self.connect ( #args ) ... end
,它的工作原理是一样的。
因为 self::whatever
对我来说是第一次,所以我想知道 self
命名空间在这种情况下到底是做什么的,在这种情况下它的真正目的是什么。任何人都可以帮助阐明这一点吗?
::
是范围解析运算符。所以 self::connect
从 self 解析 connect
。这意味着它相当于 self.connect
。你可以从这个非常人为的例子中看到它是如何工作的:
class Foo; end
class Bar
def Foo::baz
"Hello World"
end
end
puts Foo.baz # "Hello World"
当然我们也可以只使用def Foo.baz
得到完全相同的结果。
Ruby Style guide 不鼓励使用双冒号定义方法:
Do not use :: to define class methods.
# bad class Foo def self::some_method end end # good class Foo def self.some_method end end
除了引用常量和构造函数之外,也不推荐用于其他用途:
Use :: only to reference constants (this includes classes and modules) and constructors (like Array() or Nokogiri::HTML()). Do not use :: for regular method invocation.
::
在某种程度上等同于 .
。 (我将省略一个精确的定义,在哪些 exact 情况下它是等价的,以及等价到什么程度,因为我承认我自己并不完全了解它,也没有很好的记录。 )
这是 ::
和 .
行为不同的示例:
module Foo
def self.Bar
'method'
end
Bar = 'constant'
def self.Qux; end
end
Foo.Bar
#=> 'method'
Foo::Bar
#=> 'constant'
Foo::Bar()
#=> 'method'
Foo.Qux
Foo::Qux
# NameError (uninitialized constant Foo::Qux)
Foo::Qux()
[注意:这不是一个完美的例子,因为这是关于消息发送方面的事情,而你的例子是关于事情的方法定义方面的。我相信在方法定义方面,它们是 100% 相同的,因为 def
从不定义常量,因此没有歧义。]
所有风格指南都强烈反对这种用法,从强烈建议反对它的消息感知部分到完全禁止这两种用法。这样做的主要原因是两者在消息发送方面的行为不同,这可能会导致混淆。当不对两者使用相同的运算符时,解释方法查找(动态,在继承链中向上)和常量查找(首先是静态,词法向外,然后是动态,在继承链中向上)之间的概念差异也更简单。
许多 Rubyists 使用的典型风格是:
- 永远不要使用
::
作为单例方法定义,总是使用.
. - 始终使用
::
在文档中引用单例方法,永远不要使用.
。 - 始终使用
.
作为文档中消息发送(包括单例方法)的用法示例,永远不要使用::
。 - 永远不要使用
::
发送消息(包括单例方法),始终使用.
.
最后两个有时会软化以允许应该 return 模块或 类 的方法,并允许充当工厂的方法(例如 Nokogiri::XML
)通过消息调用发送 "look like" 常量查找,(例如 Nokogiri::XML('<root/>')
而不是 Nokogiri.XML('<root/>')
)。
有一个 feature request for removing this usage of ::
, but it was rejected 主要是因为向后兼容性问题。