在当前目录中存在一个下列内容的文件 mod.rb 。
module Mod
def foo
"Foo" + bar
end
private
def bar
"Bar"
end
end
请利用Mod 模块,定义具有类方法 foo 的类 Klass 。
类 Klass 的利用例如下。
puts Klass.foo
最后在终端输出 FooBar 。
--
黒田努
解答与说明的显示・隐藏
解答与说明
这是一个怎样将模块作为类方法引用的问题。
好像有一点难的样子。
MTG君在说着“很难得到正确答案”的同时,发来了下面的代码。
require 'mod'
class Klass
include Mod
end
puts Klass.new.foo
#puts Klass.foo # => undefined method `foo' for Klass:Class (NoMethodError)
一般的使用 include 方法取出模块便是这样。
下面的代码是 river125 的答案。
require 'mod'
class Klass
include Mod
def self.foo
k = Klass.new
k.foo
end
end
因为问题中写了“利用Mod 模块”,这也没错,但是要避免每次调用方法foo 都生成实例。
大詰君提供了了正确解答。
require 'mod'
class Klass
extend Mod
end
Ruby参考手册的Object,就 extend 方法 “把用参数指定的模块的实例方法作为self 特殊方法追加”进行了说明。
特殊方法是什么呢。
这是在与实例方法进行对比时使用的语言。别名为单例方法。
具有某个对象 obj 的方法,被分为实例方法和特殊方法。
实例方法被其对象的类定义,并被类的实例全体所共有。
与此相对,特殊方法在对象中被定义。
更准确的说法是,对象在所属的特殊类中被定义。
总之,被一个对象专有的方法就是特殊方法。
那么,像怎样写的时候,应该怎么做呢。
class Klass
extend Mod
end
虽然方法 extend 的运行主体 self 未在表面出现,但是直接在类定义之下,所以类 Klass 就是 self 。
请回想一下在Ruby 语言里,类即是对象。
一句话,就是将模块 Mod 作为叫做类 Klass 的“对象”的特殊方法进行追加。
实际上,“类方法”就是类的特殊方法!
* * *
最后来看示范解答。
require 'mod'
class Klass
class << self
include Mod
end
end
class << self ... end 是定义特殊类时的写法。在其中定义方法的话,就成为类 Klass 的类方法。
虽然比使用 extend 时的代码要长,但是好处是在希望添加 Klass 独自的类方法 baz 时可以这样写。
require 'mod'
class Klass
class << self
include Mod
def baz
"Baz"
end
end
end
因为明确了从模块引入的类方法与独自的类方法的关系,我喜欢下面这样的写法。
此外,还可以重写私有方法 bar 。
require 'mod'
class Klass
class << self
include Mod
private
def bar
"BAR"
end
end
end
顺便说一下,下面这样大体上也能重写,但是 bar 便成了公共方法。
require 'mod'
class Klass
extend Mod
private
def self.bar
"BAR"
end
end
虽然 private 是一个将以后的方法定义的作用域私有的方法,但对于特殊类的方法定义却没有效果。