如何使用 Ruby 的 self 关键字

Posted

技术标签:

【中文标题】如何使用 Ruby 的 self 关键字【英文标题】:How to use Ruby's self keyword 【发布时间】:2011-10-03 21:56:36 【问题描述】:

据我了解self,它指的是类的当前实例。

这难道不是一直以来的默认行为吗?例如,不是

self.var_one = method(args)

相当于

var_one = method(args) 

如果是,self有什么用?

【问题讨论】:

【参考方案1】:

这是一个例子:

def run miles
  self.miles = miles
end

在这种情况下,self 会有所帮助。在大多数情况下,self 是多余的。

【讨论】:

【参考方案2】:

有几个重要的用途,其中大部分基本上是为了消除实例方法、类方法和变量之间的歧义。

首先,这是定义类方法的最佳方式:

class Foo
  def self.bar
    "class method bar"
  end

  def bar
    "instance method bar"
  end
end

Foo.bar  #returns "class method bar"

foo = Foo.new
foo.bar #returns "instance method bar"

另外,在实例方法中self指的是实例,在类方法中它指的是类,它总是可以用来与局部变量区分开来。

class Bar
  def self.foo
    "foo!"
  end

  def baz
    "baz!"
  end

  def self.success
    foo #looks for variable foo, doesn't find one, looks for class method foo, finds it, returns "foo!"
  end

  def self.fail
    baz #looks for variable baz, doesn't find one, looks for class method baz, doesn't find one, raises exception
  end

  def instance_success
    baz #looks for variable baz, doesn't find one, looks for instance method baz, finds it, returns "baz!"
  end

  def instance_fail
    foo #looks for variable foo, doesn't find one, looks for instance method foo, doesn't find one, raises exception
  end

  def local_variable
    baz = "is my favorite method"
    baz #looks for variable baz, finds it, returns "is my favorite method"
  end

  def disambiguate
    baz = " is my favorite method"
    self.baz + baz #looks for instance method baz, finds it, looks for local variable baz, finds it, returns "baz! is my favorite method"
  end
end

因此,最终,您可以避免在许多情况下使用self,但使用它通常有助于确保您以后不会无意中产生命名冲突。有时这些会产生很难找到的错误。归根结底,这往往是个人风格的问题。


正如 cmets 所述,还有一件非常重要的事情:

在一个类中,如果你有这样的方法:

def bar=(string)
  ...
end

在你调用的另一种方法中:

def other_method
  bar = "abcd"
end

它不会调用你的bar= 方法,它会创建一个局部变量bar。因此,在这种情况下,您使用 self 告诉 Ruby 不要创建局部变量:

def other_method
  self.bar = "abcd"
end

如果你想使用方法名作为参数,同样的情况也适用:

def example
  ...
end

def other_thing(example)
  self.example(example)
end

如果你离开self,Ruby 会假设你指的是同名的局部变量。

因此,一般来说,方法名称中的self 用于区分类变量和实例变量,当Ruby 需要帮助区分方法调用和局部变量或局部变量赋值时,其他任何地方都使用它。

我希望这是有道理的。

【讨论】:

这是一个更彻底的答案,只是它不包括分配警告。还有一篇很好的关于用法的博客文章:jimmycuadra.com/posts/self-in-ruby,其中特别包括分配。不使用 self 就不能调用分配方法(如第一个答案中所述)。 对 Java 人很有帮助 =) 大概,最好概括一下“只能在类方法内部访问类变量/方法”的原则 @fengd 当然你可以使用 self.class.class_method 从实例方法调用类变量/方法 " class Person def self.class_method 'gobal variable' end def show self.class.class_method end end person = Person.new 放 person.show【参考方案3】:

self 的另一个用途是声明类方法(类似于 Java 中的静态方法)。

class foo
 def self.bar
  #do class related stuff here
 end
end

话虽如此,您也可以使用def foo.bar 代替方法签名。

【讨论】:

【参考方案4】:

在大多数情况下,self.foo 确实是多余的,因为您可以只写 foo 以获得相同的效果,但在这种情况下它不是,self 是必需的。

var_one = method(args) 将创建一个名为var_one 的局部变量,它不会调用任何方法或对self 执行任何其他操作。

self.var_one = method(args) 将使用参数method(args)self 上调用方法var_one=

另一种使用self 是非可选的情况是,如果您想将它作为参数传递给方法,即some_method(self) - 如果没有self 关键字,您将无法做到这一点。

【讨论】:

@Ankit:可以通过成为方法来成为方法。抱歉,如果这有点无法回答,但我真的不知道该怎么回答。如果你想让var_one成为一个局部变量,把self.放在它前面是错误的,不会做你想做的。 @Ankit Soni:如果您向self(例如self.foo)发送任何消息,它将调用您班级的foo 方法。 var_one= 只是一个 setter 方法。如果你想让var_one 成为一个变量,你一定不能使用self(它只对调用方法有用)。如果您正在寻找实例变量,那么您只需在标识符前面加上 @(例如,@var_one 好的我明白var_one=是setter方法。现在,即使在这种情况下,var_one= 也不会调用与 self.var_one= 相同的对象实例的相同 setter 方法吗? @Ankit:不。如果你写var = "bla",这将始终创建一个局部变量,并且永远不会调用setter方法。如果你写foo.var = "bla",它会在foo上调用setter方法var=。所以要在self 上调用var= setter 方法,你需要写self.var = "bla"。写var = "bla"不够,因为它只会创建一个局部变量。 @Ankit:您的 setter 方法将执行您定义的任何操作。但是它几乎肯定不会创建一个名为 var 的局部变量,因为该变量是局部变量,只会存在于该 setter 方法中,因此没有任何作用。如果您使用attr_accessor 定义了setter 方法,它将创建一个名为@var实例变量。所以在那种特定情况下@var = "foo"self.var = "foo" 会做同样的事情。但是var = "foo" 不会。

以上是关于如何使用 Ruby 的 self 关键字的主要内容,如果未能解决你的问题,请参考以下文章

在 Ruby 中,如何验证 Struct 的身份?

如何左移整数的位

如何在类及其方法中使用 self 参数、@staticmethod 关键字

如何在 Ruby 中编写复杂的多行 if 条件?

如何在 Ruby 中结束块的执行?

给定一个 Ruby 对象的实例,我如何获得它的元类?