2016-10-24 64 views
1

我想了解此代码。为什么它返回Hello而不是Howdy!类方法正在访问实例变量

class Speaker 
    @message = "Hello!" 

    class << self 
    @message = "Howdy!" 

    def speak 
     @message 
    end 
    end 
end 

puts Speaker.speak 

回答

-1

此代码返回“你好”的原因是,它正试图在一个类< <自身块来改变一个实例变量。

类方法适用于任何不处理该类的单个实例的任何事物 - 实例变量与类的各个实例相关联,并且我们无法在类级别更改实例变量。

而不是在说方法中使用实例变量,我们应该使用类变量(用@@表示)。

作为一个例子,下面的代码将返回'你好!' -

class Speaker 
    @@message = "Hello!" 

    class << self 
     @@message = "Howdy!" 

     def speak 
      @@message 
     end 
    end 
end 

puts Speaker.speak 
+2

上面的'@ message'是一个类级别的实例变量,它属于'Speaker'类,它本身作为一个对象是类'Class'的一个实例:'Speaker.class#=> Class','Speaker .instance_variables#=> [:@message]' –

4

首先,你的消息@message不是一个实例变量,或者更确切地说,没有实例变量,你可能会思考型:这是一个类级别的实例变种,所以Speaker本身就是一个实例变量,其作为对象是类Class的实例。

下面的代码的版本,那么你想要什么有局部变量和闭合的事情:

class Speaker 
    @message = "Hello!" 

    class << self 
    message = "Howdy!" 
    define_method(:speak) { message } 
    end 
end 

Speaker.speak 
#=> "Howdy!" 

,这里是一些代码,说明类级别的实例变量之间的差异一个“正常”的实例变量:

class Speaker 
    @message = 'Howdy!' # class-level instance variable 

    def initialize 
    @message = 'Hello!' # instance variable of Speaker's instances 
    end 

    def speak 
    @message 
    end 

    class << self 
    def speak 
     @message 
    end 
    end 
end 

Speaker.speak 
#=> "Howdy!" 
Speaker.new.speak 
#=> "Hello!" 
3

这里是你的代码,但我已经定义通常的方式(def self.speak...)类方法。由于类方法不过是在类的单例类上定义的实例方法,所以这种更改仅仅是创建相同类方法的不同方式。 (如果你怀疑这种情况,请在两种方式下运行代码。)我做了这个改变,因为我认为这会让我解释清楚的事情。我还添加了一个puts声明。

class Speaker 
    @message = "Hello!" 

    def self.speak 
    puts "self=#{self}" 
    @message 
    end 

    class << self 
    @message = "Howdy!" 
    end 
end 

类定义的第一行创建一个类的实例变量@message

Speaker.instance_variables 
    #=> [:@message] 
Speaker.instance_variable_get(:@message) 
    #=> "Hello!" 

通过constrast,

@message = "Howdy!" 

上创建Speaker的单件类的一个实例变量:

Speaker.singleton_class.instance_variables 
    #=> [:@message] 
Speaker.singleton_class.instance_variable_get(:@message) 
    #=> "Howdy!" 

现在在Speaker调用speak

Speaker.speak 
    # self=Speaker 
    #=> "Hello!" 

由于self #=> Speakerspeak显然是返回类实例变量的值。

对于speak返回上Speaker的单个类中定义的实例变量的值,我们可以写出如下:

class Speaker 
    @message = "Hello!" 

    def self.speak 
    puts "self=#{self}" 
    puts "singleton_class = #{singleton_class}" 
    singleton_class.instance_variable_get :@message 
    end 

    class << self 
    @message = "Howdy!" 
    end 
end 

puts Speaker.speak 
    # self=Speaker 
    # singleton_class = #<Class:Speaker> 
    # Howdy! 

在最后一个表达式,因为self等于Speakerself是隐含的接收器时没有明确的接收方,"singleton_class相当于Speaker.singleton_class