Ruby 这里到底要不要加 self?

jiffies · April 17, 2012 · Last by hysios replied at April 18, 2012 · 3245 hits
before_save :create_remember_token
private
   def create_remember_token
     self.remember_token = SecureRandom.urlsafe_base64
   end

请问这里,self.remember_token 的 self 能否去掉?不加 self 好像运行不正常,但是不应该默认是 self 的么

虽然不知道代码引用自那里,如果不加 self 运行不正常,很显然,remember_token 应该是 protected 方法。

不加 self 相当于是给一个临时变量 remember_token 赋值,加 self,相当于是调用 remember_token=(...) 这个方法。2 者完全不同的。

#2 楼 @quakewang 也就是说本来在实例方法中调用的方法默认接收者应该是 self,可以不写。但是唯有写者方法不行?

self 是当前的正在运行的代码的 context 上下文的引用,如果记得没错的话,这个跟 Ruby 方法的查询方式和优先级有关。

如果是一个 ActiveRecord 对象,那么在对象初始化的时候,会根据表字段,给每个字段生成一对 get / set 方法,比如remember_tokenremember_token=(value)这两个方法。第二个 set 方法如果在另外一个方法内被调用的时候,在没有添加 self 的时候,会优先处理为你想要声明一个局部变量,而不是去尝试调用之前生成的remember_token=(value)方法,如果显示声明了 self 后,则告诉 Ruby 解释器你这里不是要声明一个局部变量,而是一个 set 方法调用。

想要理解 Ruby 解释器为什么这样排列优先级的话,不如反过来思考,如果解释器的查询逻辑刚刚好相反的话,你要怎样才能明确的告诉解释器你这里要声明一个跟表字段同名的局部变量,而不是去调用 set 方法呢?

#2 楼 @quakewang 正解,不过你真快啊,我提交后才发现原来这个问题已经被你给秒掉了。

#4 楼 @lgn21st 是不是只有 set 方法有这样的问题?

#7 楼 @jiffies 和 setter 关系不大,关键是 ruby 支持没有括号的方法调用,看“双飞燕”书里第 4.5.1 这部分的内容

#8 楼 @fsword 可是我觉得是 set 的问题啊,因为支持 fun=这样的函数跟一般的变量赋值冲突了才会这样,其他函数就不会吧

如果 remember_token 为私有方法,不能加 self

#9 楼 @jiffies 嗯,我说的不准确,不过你还是先看书吧,上面说的很详细

#10 楼 @hysios 如果那样就只能 send(:remember_token=, value) 了

@doitian 不会吧,应该是直接 remember_token = value

#13 楼 @hysios 直接就成临时变量

class Foo
  def test=(value)
    puts "test=#{value}"
  end

  def run
    self.test = 1
    test = 2

    send :ptest=, 3
    ptest = 4
  end

  private
  def ptest=(value)
    puts "ptest=#{value}"
  end
end

Foo.new.run
# test=1
# ptest=3


是呀 @hysios 大婶,不加 self 的话就是 local var 了

@doitian private assignment method 是个例外 ,其它的没有问题,我忘了这个细节了

class Foo
  def test=(value)
    puts "test=#{value}"
  end

  def run
    self.test = 1
    test = 2

    ptest 4
  end

  private
  def ptest(value)
    puts "ptest=#{value}"
  end
end

Foo.new.run
test=1
ptest=4


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