Module与访问权限 #
Module #
模块提供了一个命名空间,并避免名称冲突。在 Ruby 中,类其实就是特殊的模块。默认模块外的代码全部都在 main
命名空间中。
定义模块 #
utils.rb
puts 'load module'
COUNT = 10 # => main 命名空间
module StrUtils
COUNT = 20 # => StrUtils 命名空间
def sort_words(words)
words.sort
end
def self.echo
puts "#{COUNT} #{::COUNT}"
end
end
其中 self
关键字用于定义模块自身的函数,而没有使用 self
仅仅表示在特定的命名空间内定义了一个函数。
: 与 :: #
:
用于构建 Symbol 对象
::
表示对命名空间的引用。上节例子中 echo()
函数中的 ::COUNT
就表示引用 main
命名空间的常量。
require #
require
用于引入模块,只会被导入一次,重复导入会被忽略,且引入时不包含后缀名。
require './utils'
require './utils'
StrUtils.echo # => 20
puts StrUtils::COUNT # => 20 10
load #
load
类似 require
,但是必须包含后缀名,且会被引入多次,所以如果重复引入包含同个常量的模块时会报已经定义的异常。
load './utils.rb'
StrUtils.echo
include #
include
相当于 Java 中的 import
,会将模块中定义的函数直接复制到当前命名空间中,所以调用时可以省略前缀。
include StrUtils
# puts echo()
sentents = ['z', 'b', 'e', 'p']
puts StrUtils.sort_words(sentents)
puts sort_words(sentents)
include
还有一个特点是,当一个模块被包含时该模块的 included
方法会被自动调用。
module StrUtils
def self.included(clazz)
puts "StrUtils is included in #{clazz}"
end
end
以上例子中当 StrUtils
被 include
时,方法会被调用,传入的参数为当前类对象。
extend #
extend
功能类似 include
,但是 include
是实例级别的(混入的方法由实例调用),而 extend
默认是类级别的(混入的方法由类调用)。
module C
def c1
puts 'c1'
end
end
class Sample
extend C
end
Sample.c1
同 include
一样,extend
也有一个回调方法
def self.extended(base)
puts "A is extended in #{base}"
end
extend
还有一个特点是其可以作用在实例上动态 extend
任何对象。结合 included
方法可以在某个模块被包含时动态为启动包含的对象添加新的 extend
。
samp = Sample.new
samp.extend C
samp.c1
混合类型 #
Ruby 中使用模块加 include
可以使类变为混合类型,实现类似多重继承的功能。
module A
def a1
puts 'a1'
end
def a2
puts 'a2'
end
end
module B
def b1
puts 'b1'
end
def b2
puts 'b2'
end
end
class Sample
include A
include B
def s1
puts 's1'
end
end
samp = Sample.new
samp.a1
samp.a2
samp.b1
samp.b2
samp.s1
Class 与 Module #
Ruby 中声明 Class 与 Module 通常使用的是常量,但是也可以像普通变量一样进行声明
dog = Module.new do
def speak
puts 'speak'
end
end
cat = Class.new do
def jump
puts 'jump'
end
end
kitty = cat.new
kitty.extend(dog)
kitty.speak
访问权限 #
Ruby 中访问权限分为 public
, private
和 protected
。默认的访问权限为 public
。protected
只能由子类调用。
class Dog
def initialize(name, breed)
@name = name
@breed = breed
end
public
def bark
puts 'Woof!'
end
def echo
puts info # => 调用 private 方法
end
private
def info
"name=#{@name}, breed=#{@breed}"
end
protected
def jump
puts 'Jump!'
end
end
class SuperDog < Dog
def fly
jump # => 调用父类的 protected 方法
puts 'fly'
end
end
dog = Dog.new('Clark', 'foobar')
dog.bark # => 调用 public 方法
dog.echo # => 调用 默认 public 方法
super_dog = SuperDog.new('Super Clark', 'foobar')
super_dog.fly
冻结对象 #
Ruby 可以通过 freeze
来冻结对象。冻结对象后,任何修改都是无效的,会直接报 can't modify frozen
异常。
dog.freeze
# can't modify frozen Dog
# dog.breed = 'bar'
if dog.frozen?
puts 'frozen object'
else
puts 'normal object'
end