Ruby Ruby 的 private method 以"="结尾时的疑惑

ziu · August 15, 2015 · Last by ziu replied at August 16, 2015 · 2347 hits

在 ruby 中,private method 不能被显式调用,即使是 self 调用也不行,但是在这种情况下:

class A
  def say_hi
    puts 'hi'
  end

  def word=(w)
    @word=w
  end

  private :word=, :say_hi

  def method1

    say_hi  #ok (1)
    self.say_hi  #error,不能显示调用 (2)

    ###调用同为私有方法 的 word
    word="hello" #ok, 但不是调用了word method 而是创建了一个临时变量word (3)
    self.word "hello"  # 可以!!  Ruby在内部里边到底是如何判断哪些私有方法可以被self调用,而且是如何实现的? (4)

  end
end






而且这么做有何意义?这种情况貌似只会发生在私有方法名以=结束的情况下。 在stackoverflow上有类似提问,解答是为了避免歧义性 You are correct in assuming this is to avoid ambiguity. It's more a safeguard to the potential harm of ruby's dynamic nature. It ensures that you cannot override accessors by opening up the class again later. A situation that can arise, for example by eval'ing tainted code. 但我还是不太明白。

烦请问一下有谁了解这是为何吗? 谢谢!

private 方法只能在类里隐式调用,protected 方法只能在类里隐式或显示调用 (self), 但 ruby 一些动态方法可以在外部调用 private, protected 方法,例如 Object#send, Method#call

#1 楼 @chaucerling 嗯,谢谢。这些我知道的。我是困惑于当私有方法以=结束时,必须以self调用,在 Ruby 内部是如何将其和一般的私有方法的调用机制区分开的?难不成私有方法分成两类?

#2 楼 @ziu =属于 assign,确实是特殊的,和普通私有方法不同

require 'ripper'
require 'pp'

def test= n
  puts 1
end

def test n
  puts 2
end

private :test=, :test

code =<<EOF
self.test= 12
self.test 15
EOF

pp Ripper::sexp(code)
[:program,
 [[:assign,
   [:field,
    [:var_ref, [:@kw, "self", [1, 0]]],
    :".",
    [:@ident, "test", [1, 5]]],
   [:@int, "12", [1, 11]]],
  [:command_call,
   [:var_ref, [:@kw, "self", [2, 0]]],
   :".",
   [:@ident, "test", [2, 5]],
   [:args_add_block, [[:@int, "15", [2, 10]]], false]]]]

test= 解析出来的操作是把参数 assign 给对象的属性

私有方法为=结尾,如果不显式调用,就和局部变量赋值产生歧义,所以只有对象的属性能自定义 assign 的方法

关于 ruby 比较底层的机制,推荐书籍 Ruby Under A Microscope,很快有中文版【貌似

#3 楼 @cicholgricenchos 谢谢!通过这个Ripper貌似理解了一点点。但请问所以只有对象的属性能自定义assign的方法是什么意思?

You need to Sign in before reply, if you don't have an account, please Sign up first.