【问题标题】:Ruby - How to access instance variables from classes with "self" methods?Ruby - 如何使用“self”方法从类中访问实例变量?
【发布时间】:2020-03-15 03:26:57
【问题描述】:

抱歉,我不知道如何命名,我很难查找此内容因为我不知道该怎么说。总之……

假设我有一个如下所示的类:

class Run
    def self.starting
        print "starting..."
    end
    def self.finished
        print "Finished!"
    end
end

Run 中的所有方法前面都有self,这意味着我不必做run = Run.new,我可以只做Run.starting。现在假设我想添加一些实例变量...

class Run
    attr_accessor :starting, :finished
    def self.starting
        print "starting..."
        @starting = true
        @finished = false
    end
    def self.finished
        print "finished!"
        @starting = false
        @finished = true
    end
end

如果我想从类外部访问这些实例变量怎么办?我知道像print "#{Run.finished}"print "#{Run.starting}" 这样的东西不会做任何事情。如果没有run = Run.new,我可以这样做吗?或者我应该删除self,然后使用run = Run.new? (对不起,如果这个问题是一团糟。)

【问题讨论】:

  • attr_accessor 创建 getter 和 setter 方法,这些方法可以发送到类的 instances 以检索或设置该实例的实例变量的值。 @starting@finishedclass 实例变量。要为这些变量创建访问器,您需要在 Runs 单例类中执行 attr_accessorclass << self; attr_accessor :starting, finished; end。 (试试看。)

标签: ruby instance-variables


【解决方案1】:

Run 中的所有方法前面都有 self,这意味着我不必执行 run = Run.new,我只需执行 Run.starting

它的意义远不止于此。在您的情况下,您正在调用类方法。如果您执行了runner = Runner.new - 那么您将调用实例方法(这些方法是在没有self 的情况下定义的。

一般来说,如果您需要“事物”来保持某种状态(如@running = true),那么您宁愿实例化一个对象并调用这些方法。

现在,@whatever 是实例变量,您无法在类方法中访问它们。

class Run
   attr_reader :running
   def start
      @running = true
   end

   def stop
      @running = false
   end
end

runner = Run.new
runner.running # nil
runner.start
runner.running # true
runner.stop 
runner.running # false

我建议你做一些关于 Rails 编程的教程或基础级别的书,找一章关于对象和类。做一些练习。

【讨论】:

    【解决方案2】:

    在 Ruby 中,实例变量只是作用于类实例的词法变量。因为它们的作用域是实例,所以它们总是像私有变量一样。

    如果您想从外部提供对实例变量的访问,您可以创建 setter 和 getter 方法。这就是attr_accessor 所做的。

    class Person
      attr_accessor :name
    
      def initialize(name:)
        @name = name
      end
    
      def hello
        "Hello my name is #{@name}"
      end
    end
    
    john = Person.new(name: 'John')
    john.name = "John Smith"
    puts john.hello # "Hello my name is John Smith"
    puts john.name # "John Smith"
    

    def self.foo 定义的方法是类方法,也称为单例方法。您不能从类方法内部访问属于实例的变量,因为调用该方法时的接收者是类本身,而不是类的实例。

    Ruby 还具有由类及其子类共享的类变量:

    class Person
      @@count = 0
    
      def initialize
        self.class.count += 1
      end
    
      def self.count
        @@count
      end
      def self.count=(value)
        @@count = value
      end
    end
    
    class Student < Person
    end
    
    Person.new
    Student.new
    puts Person.count # 2 - wtf!
    

    以及不与子类共享的类实例变量:

    class Person
      @count = 0 # sets an instance variable in the eigenclass
    
      def initialize
        self.class.count += 1
      end
    
      def self.count
        @count
      end
      def self.count=(value)
        @count = value
      end
    end
    
    class Student < Person
      @count = 0 # sets its own class instance variable
    end
    
    Person.new
    Student.new
    puts Person.count # 1
    

    类变量不经常使用,通常包含对数据库连接或配置的引用,这些内容由类的所有实例共享。

    【讨论】:

      【解决方案3】:

      您不能从实例外部访问实例变量。这就是实例变量的全部意义所在。

      您可以从实例外部访问的唯一内容是(公共)方法。

      但是,您可以创建一个返回实例变量的公共方法。这样的方法在 Ruby 中称为 attribute reader,其他语言可能称之为 getter。在 Ruby 中,属性读取器通常与实例变量命名相同,但在您的情况下这是不可能的,因为已经有名称为 startingfinished 的方法。因此,我们必须为属性读取器找到一些其他名称:

      class Run
        def self.starting?
          @starting
        end
      
        def self.finished?
          @finished
        end
      end
      

      由于这是一个常见操作,因此有一些辅助方法可以为您生成这些方法,例如Module#attr_reader。但是,他们还假设属性读取器方法的名称与实例变量的名称相同,因此如果您要使用此辅助方法,它将覆盖您已经编写的方法!

      class << Run
        attr_reader :starting, :finished
      end
      

      当你这样做时,你会得到警告(你在开发时总是打开警告,是吗?)告诉你你已经覆盖了你现有的方法:

      run.rb:19: warning: method redefined; discarding old starting
      run.rb:2: warning: previous definition of starting was here
      run.rb:19: warning: method redefined; discarding old finished
      run.rb:5: warning: previous definition of finished was here
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-12-20
        • 1970-01-01
        • 2012-01-07
        • 2012-03-07
        • 2021-06-03
        • 2013-07-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多