使用@符号在函数内添加变量前缀的目的是什么?

时间:2013-08-13 22:22:53

标签: ruby

我理解类中的实例变量可以通过在变量名前加上@符号来表示。在类What does @@variable mean in Ruby?

中有一些实际应用

在函数内部执行此操作的实际应用是什么?

def foo
    one = 1
    @two = 2
end

3 个答案:

答案 0 :(得分:4)

这是实例变量。它的值在一个实例上持续存在。

class Foo
  def set_baz
    @baz = 1
  end

  def get_baz
    @baz
  end
end

foo = Foo.new
foo.get_baz #=> nil
foo.set_baz
foo.get_baz #=> 1


foo2 = Foo.new
foo.get_baz #=> nil

正如您所看到的,我们可以在任何方法中设置@baz,并在实例上更新,我们可以在以后获取它。


@前缀设置并获取self上的实例变量,无论self是什么。假设我启动irb,现在self是为运行代码而创建的对象上下文。当您使用自己的代码创建自己的类时,self的值(也称为上下文) )将在整个应用程序中以各种方式进行更改。

2.0.0-p0 :001 > @foo = 123
 => 123 
2.0.0-p0 :002 > self.instance_variable_get :@foo
 => 123 
2.0.0-p0 :003 > self
 => main
2.0.0-p0 :004 > self.class
 => Object

但实际上,除非你在一个类中,否则我不会设置实例变量。你只会让自己感到困惑,并没有很好的理由去做。

我会说,根据经验,如果你不确切地知道代码行中self 是什么,你不应该设置实例变量它根本就没有。

答案 1 :(得分:0)

您的问题表明您可能会@@@混淆。前者与某个类的特定实例相关联;后者由该类的所有对象共享。扩展亚历克斯的答案:

class Foo
  def set_baz(n)
    @baz = n
  end

  def set_zoo(n)
    @@zoo = n
  end

  def get_baz
    @baz
  end

  def get_zoo
    @@zoo
  end
end

foo = Foo.new
bar = Foo.new

foo.set_baz(1) 
foo.get_baz   # 1

bar.set_baz(2)
bar.get_baz   # 2

foo.get_baz   # still 1

foo.set_zoo(3) 
foo.get_zoo   # 3

bar.set_zoo(4) 
bar.get_zoo   # 4

foo.get_zoo   # also 4

答案 2 :(得分:0)

  

函数方法中执行此操作的实际应用是什么?

class Dog
  def foo
    one = 1
    @two = 2
  end

  def bar
    puts @two
    puts one
  end

end

d = Dog.new
d.foo
d.bar

--output:--
2

1.rb:9:in `bar': undefined local variable or method `one' for #<Dog:0x00000101086810 @two=2> (NameError)
    from 1.rb:16:in `<main>'

当方法完成执行时,局部变量(在它们前面没有@的变量)将被销毁。

  

是的 - 但是这在常规函数中意味着什么,而不是类的方法?

实例变量,在它们前面有一个@的实例变量,将它们自身附加到创建它们时的任何对象:

def do_stuff
  puts self   #=>main
  @val = 10
end

do_stuff   

puts self  #=>main

该输出有点不寻常,因为self在def内部和def外部等于名为main的对象。通常def会改变自我 - 但是当def处于顶层时def不会改变自我。

好的,如果@val附加到名为main的对象,并且self = main,则打印出@val:

def do_stuff
  puts self   #=>main
  @val = 10
end

do_stuff 

puts self.val  #`<main>': undefined method `val' for main:Object (NoMethodError)
是啊,是的。默认情况下,所有实例变量都是私有的,所以让我们在main的类中编写一些访问器:

def do_stuff
  puts self   #=>main
  @val = 10
end

do_stuff

puts self.class   #=>Object

class Object
  attr_reader :val
end

puts self.val   #=>10

接下来,def会在创建def时附加当前类。当前类等于self,或者如果self不是类,则当前类是self的类。在上面的示例中,当do_stuff创建时self = main:

puts self    #main

def do_stuff
  puts self
  @val = 10
end

因为self不是一个类,所以当前的类是self的类,我们可以看到它是Object:

puts self.class   #Object

所以do_stuff将自己附加到Object类,这意味着它成为Object类的实例方法。对于额外的点 - 它实际上变成了一个私有实例方法:

puts Object.private_methods.grep(/^do/)   #=>do_stuff
内部类的defs也将自己附加到当前类:

class Dog
  puts self   #=>Dog

  def bark
    puts "Woof"
  end
end

...但与顶层不同,defs成为该类的公共实例方法。