美文网首页
Ruby元编程

Ruby元编程

作者: youngiii | 来源:发表于2017-10-04 11:17 被阅读40次
    • 方法
    • 代码块
    • 类宏
    • Eval方法

    实例变量、方法、类

    实例变量(Instance Variables)是当你使用它们时,才会被建立的对象。因此,即使是同一个类的实例,也可以有不同的实例变量。

    从技术层面上来看,一个对象(实例)只是存储了它的实例变量和其所属类的引用。因此,一个对象的实例变量仅存在于对象中,方法(我们称之为实例方法(Instance Methods))则存在于对象所属的类中。这也就是为什么同一个类的实例都共享类中的方法,却不能共享实例变量的原因了。

    • 类也是对象。
    • 因为类也是一个对象,能应用于对象的皆可运用于类。类和任何对象一样,有它们自己的类,Class类即是Class类的实例。
    • 与其它的对象一样,类也有方法。对象的方法即是其所属类的实例方法。亦即,任何一个类的方法就是Class类的实例方法。
    • 所有的类有共同的祖先Object类(都是从Object类直接或间接继承而来),而Object类又继承自BasicObject类,Ruby类的根本。
    • 类名是常量(Constant)。
      n = Class.new
      puts n.ancestors
      puts n.supperclass
      puts n.supperclass.supperclass
      puts n.supperclass.supperclass.supperclass
    

    打开类

    其实这个就跟方法重定义是一样的结果,不过随意改动可能会产生严重的后果,比如说你改的这个方法在其它地方有使用到,所以这种方法还是慎用,除非你非常明确该方法不会造成其它后果。

    puts 'abc'.replace('a') # a
    class String
      def replace(string)
        puts '重新打开了类'
      end
    end
    'abc'.replace('a')  #'重新打开了类'
    

    我们也可以使用细化来实现这个过程

    细化

    module StringExtensions
      refine String do
        def replace(string)
           puts '细化'
        end
      end
    end
    

    在需要使用这个方法的地方使用using

    如:using StringExtensions
    细化的好处就是不会全局影响,在你需要使用的地方using就可以了,风险相对较小。

    调用方法

    类中的方法是怎么调用的?

    • 方法的查找(接收者和祖先链)
      Ruby中要在类中查找一个方法,首先在它的类查找这个方法,如果没有,则往上查找,如此类推,直到祖先链的顶端,到最后,如果还没找到,会抛出method_missing异常。如果有了解过JS,那么你肯定非常明白这个过程,因为JS中的方法查找也是类似于这个过程。
    • 执行方法
      在执行方法的过程中,Ruby始终需要一个接收者的引用,也就是self

    self关键字

    任何时刻,Ruby中只有一个对象能充当当前对象,并且没有哪个对象能长期充当这个角色,调用一个方法时,接收者就成为了self,从这一刻起,所有的实例变量都是self的实例变量,所有没有明确指明接收者的方法都在self上调用。
    举个栗子:

    class Book
      def get_library
        @book_count = 1000
        self
      end
    
      def self.is_my_book?(book)
        false
      end
    end
    b = Book.new
    b.get_library # 这个时候,b就充当了self
    b.is_my_book?('Ruby元编程') # undefined method `is_book?' for #<Book:0x00000002b92268 @library=1000> (NoMethodError)
    Book.is_my_book?('Ruby元编程') # false
    

    上面调用is_my_book?的方法为什么会报错?
    那是因为 self.is_my_book?(book) 等于 Book.is_my_book?(book)
    当b调用的时候,self引用b实例对象,不等于Book,所以就会抛出找不到方法的错误

    方法

    • 动态派发(调用方法:对象.send(方法名,参数))
    class Book
      def create_book
        'Ruby元编程'  
      end  
      
      def update_book  
        'Ruby元编程'  
      end  
      
      def delete_book
        'Ruby元编程'    
      end  
    
      def search_book
        'Ruby元编程'  
      end
    end  
      
    s = Book.new  
      
    puts s.send(:get_one_name)   
    puts s.send(:get_two_name)  
    puts s.send(:get_three_name) 
    puts s.send(:get_four_name)  
    
    • 动态定义
    class Book
      ['create', 'update', 'delete', 'search'].each do |item|
        define_method("#{item}_book"){
          puts "#{item}-Ruby元编程"
        }
      end
    end
    b = Book.new
    b.create_book # create-Ruby元编程
    b.update_book # update-Ruby元编程
    b.delete_book # delete-Ruby元编程
    b.search_book # search-Ruby元编程
    
    • method_missing(幽灵方法)
    # encoding: utf-8
    class Book
      def method_missing(name, *argc)
        if [:create_book, :update_book, :delete_book, :search_book].include?(name)  
          puts "#{name}-Ruby元编程" 
        else
          super  
        end
      end
    end
    b = Book.new
    b.create_book# create-Ruby元编程
    b.update_book# update-Ruby元编程
    b.delete_book # delete-Ruby元编程
    b.search_book# search-Ruby元编程
    b.book # undefined method `book'
    

    代码块

    ...

    类宏

    如果按照以前的做法,定义一个属性的读写必须将每个属性定义一个Get 和 Set方法,比如如下代码

    class Post
      def title=(title)
        @title = title
      end
      def title
        @title
      end
     ....
     ....
    

    如果像一篇文章这样,定义title,content,author等属性,就需要写3组这样的方法,非常不方便。这个时候,就要亮出Ruby的类宏attr_accessor(module的类里面的一个C语言写的方法,附上超链接,以上代码就可以写成

      class Post
        attr_accessor :title
      end
    

    Eval方法

    相关文章

      网友评论

          本文标题:Ruby元编程

          本文链接:https://www.haomeiwen.com/subject/wnenlxtx.html