Ruby实例方法约束简谈

栏目: Ruby · 发布时间: 5年前

内容简介:在Ruby的实例方法中分别有在类词法作用域中直接定义的实例方法都是公有方法。公有方法既可以在类词法作用域内部被其他实例方法调用,也可以在作用域外部创建实例并直接调用,简单举个例子上述定义的

Ruby 的实例方法中分别有 public , private 以及 protected 三种类型,不同类型的方法将会有不一样的访问约束。而这篇文章我主要想详细介绍一下他们之间的区别。

Ruby实例方法约束简谈

1. public方法

在类词法作用域中直接定义的实例方法都是公有方法。公有方法既可以在类词法作用域内部被其他实例方法调用,也可以在作用域外部创建实例并直接调用,简单举个例子

class Person
  def initialize(first_name, last_name)
    @first_name = first_name
    @last_name = last_name
  end

  def message
    "Hello #{full_name}!!!"
  end

  def full_name
    "#{@first_name} #{@last_name}"
  end
end

@p = Person.new("zhiheng", "Lan")

puts @p.full_name # => zhiheng Lan
puts @p.message # => Hello zhiheng Lan!!!
复制代码

上述定义的 Person#messagePerson#full_name 都是公有的实例方法。

  1. 我们可以在实例化 Person 类之后,直接通过实例变量 @p 来直接调用 Person#full_name 方法。
  2. 当实例变量 @p 显式调用 Person#message 的时候,该方法会在内部调用 Person#full_name 方法。

2. private方法

许多时候我们并不希望把实例方法暴露到词法作用域之外,被创建的实例直接调用。这个时候就可以考虑把这些方法定义为私有方法。

Java 语言不同,在Ruby中我们并不需要在定义私有方法的时候在每个方法前面加上 private 关键字,而只需要分配一块 私有区域 把所有的私有方法都写在这个区域里面。接下来我们把原有的 Person#full_name 方法设置成私有方法,并添加一个名为 Person#greet 的私有方法

class Person
  def message
    "#{greet} #{full_name}!!!"
  end

  private
    def full_name
      "#{@first_name} #{@last_name}"
    end

    def greet
      "Hi,"
    end
end

@p = Person.new("zhiheng", "Lan")

puts @p.greet
#=> NoMethodError: private method `greet' called for #<Person:0x00007f8598011dd0>

puts @p.full_name
# => NoMethodError: undefined method `full_message' for #<Person:0x00007f8598011dd0>

puts @p.message
# => Hi, zhiheng Lan!!!
复制代码

PS: 对私有区域的代码进行缩进似乎是社区里面常有的做法。

可见, Person#greetPerson#full_name 这两个方法我们无法再通过实例直接调用,因为他们已经被私有化了。但是在类词法作用域内部 Person#full_name 依然可以被 Person#message 这个实例方法调用。

3. protected方法

保护方法与私有方法之前的区别比较微妙。他们之间的相同点都是不能在类词法作用域之外被实例直接调用,但比起保护方法它的约束更多

在类词法作用域内,我们无法给予私有方法一个确切的接收者。

举个例子,分别定义一个私有方法以及一个保护方法,并在类词法作用域内部通过另外一个实例方法来调用他们

class Person
  def call_method
    puts protected_method
    puts private_method

    puts self.protected_method
    puts self.private_method # will raise error
  end

  private
    def private_method
      "I am private method"
    end

  protected
    def protected_method
      "I am protected method"
    end
end

@p = Person.new("zhiheng", "Lan")
@p.call_method
 # => I am protected method
 # => I am private method
 # => I am protected method
 # => NoMethodError: private method `private_method' called for #<Person:0x00007f8598011dd0>
复制代码

可见,如果给私有方法添加一个显式的接收者 self 的话,它就会报错了,而保护方法在这种情况下却可以正常运行,这就是他们之间最大的不同。

再举个例子,添加一个方法 Person#== 用来判断两个 Person 实例是否是同一个人(只要 Person#full_name 相同则认为是同一个人)。

class Person
  def ==(other)
    self.full_name == other.full_name
  end
end

@lan = Person.new("zhiheng", "Lan")
@liang = Person.new("haidao", "Liang")

puts @lan == @liang
# => NoMethodError: private method `full_name' called for #<Person:0x00007f85990f91c0>
复制代码

因为之前的 Person#full_name 方法被定义成私有的了,所以这个时候显式为它指定接收者 self 的话就会抛出异常。解决方案就是把它重新定义为一个保护方法

class Person
  def ==(other)
    self.full_name == other.full_name
  end

  protected
    def full_name
      "#{@first_name} #{@last_name}"
    end
end

@lan = Person.new("zhiheng", "Lan")
@liang = Person.new("haidao", "Liang")

puts @lan == @liang
# => false
复制代码

比起公有以及私有方法,保护方法的应用范围似乎并不是那么多,但理解他们之间的区别对于我们这些Ruby程序员来说还是很有必要的。

4. Ruby的私有方法真的有那么私有吗?

Ruby给予了 程序员 最大的自由度,公私有方法在Ruby中与其说是约束,还不如说是 分类 。在词法作用域外部,对象通过 Object#send 方法依然可以直接调用私有方法,例子如下

class Say

  private
    def hello
      "Hello World"
    end
end

@s = Say.new

@s.hello
# => NoMethodError: private method `hello' called for #<Say:0x007fc44e929130>
@s.send(:hello)
# => "Hello World
复制代码

用这种黑科技来调试方法还是很方便的。

你能够做任何事情,但你要你清楚自己在做什么。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

WEBMASTER技术手册

WEBMASTER技术手册

斯潘奥尔 / 斯潘奥尔 / 清华大学出版社 / 2004-4 / 63.0

本书的第三版升级到Apache PHP和Java Script 最新的版本上。同是它还包含了关于mod_perl更为详尽的信息以及提高Web 性能的方法。书中的内容涉及到HTML4.01、CSS、XML和XSLT、JavaScript1.5 、HTTP1.1、A pache2.0等等。一起来看看 《WEBMASTER技术手册》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换