如何使用 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 关键字的主要内容,如果未能解决你的问题,请参考以下文章