首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Ruby元编程(读书笔记)-第1章

Ruby元编程(读书笔记)-第1章

原创
作者头像
程序员小涛
修改2021-01-28 09:56:03
4490
修改2021-01-28 09:56:03
举报

第1章 元这个字眼

元编程是编写能写代码的代码

1.1 鬼城与自由市场

语言构件(language construct)包含各种成员(变量、类、方法等)。

以C++为例,一旦编译器完成了工作,变量和函数这样的东西就变得看不见摸不着了,它们只存在于内存中。你没有办法向一个类询问它的实例方法,因为当你问出这个问题时,它可能已经消失了。对于C++这样的语言来说,运行时(runtime)是一个可怕的寂静之地----鬼城。

而在另外一些语言(如Ruby)中,运行时更像是一个繁忙的自由市场。大多数语言构件依然存在,而且正四处忙碌着。你甚至可以抓住一个构件,询问它关于它自身的问题。这种方式称作内省(introspection)

让我们通过一个实例来看看内省究竟是什么。

class Greeting
    def initialize(text)
        @text = text
    end
    
    def welcome
        @text
    end
end

my_object = Greeting.new("Hello")

这里定义了一个Greeting类,并创建了一个Greeting对象。现在我们可以抓住这个对象,并像它提问:

my_object.class #=> Greeting

我问它所属的类,它十分肯定的回答我:“我是一个Greeting”,现在我要问它有哪些实例方法:

my_object.class.instance_methods(false) #=> [:welcome]

我得到的回答是一个数组,其中只有一个方法welcome。参数false代表我是问它自己的方法,不要它继承来的方法。接着,我问它有哪些实例变量:

my_object.instance_variables #=> [:@text]

它如实回答了我的问题。类和对象都是Ruby世界的一等公民,你可以问出很多信息来。

ruby
ruby

Ruby除了可以在运行时询问语言构件,还能在运行时创建它们。在程序运行时,能否在welcome方法之外再添加一个实例方法?你可能不太理解,究竟什么情况下会有这样的需求呢?请看下面的故事。

1.2 程序员Bob的故事

Bob有一个计划:为电影迷建造一个世界最大的互联网社交系统。为了实现这个目标,他先要建立一个存放电影名和影评的数据库。Bob希望借此机会练习编写可重用的代码,因此他决定创建一个简单的代码库,用于在数据库中实现对象的持久化。

1.2.1 Bob的第一次尝试

Bob编写了一个代码库,把数据库中的每个表映射到一个类中,同时把每条记录映射到一个对象中。每当创一个对象或访问它的属性时,这个对象会产生一条SQL语句并发送给数据库。所有这些功能都封装在一个类中。

class Entity
    attr_reader :table, :ident
    def initialize(table, ident)
        @table = table
        @ident = ident
        Database.sql "INSERT INTO #{@table} (id) VALUES (#{@ident})"
    end
    
    def set(col, val)
        Database.sql "UPDATE #{@table} SET #{col}='#{val}' WHERE id=#{@ident}"
    end
    
    def get(col)
        Database.sql ("SELECT #{col} FROM #{@table} WHERE id=#{@ident}")[0][0]
    end
end

在Bob的数据库中,每个表都有一个id字段。每个Entity会保存这个字段的内容以及它引用的表名。每创建一个Entity对象后,该对象会把自己保存在数据库里。Entity#set方法创建SQL语句更新字段值,而Entity#get方法创建SQL语句读取字段值。(Bob的Database类用二维数组作为返回的数据集)

Bob可以继承Entity类来映射一个指定的表。例如,用Movie类映射一个名为movies的表:

class Movie < Entity
    def initialize(ident)
        super "movies", ident
    end
    
    def title
        get "title"
    end
    
    def title=(value)
        set "title", value
    end
    
    def director
        get "director"
    end
    
    def director=(value)
        set "director", value
    end
end

Movie类的每个属性有两个方法:一个读方法和一个写方法。Bob只要在Ruby命令行解释器中输入如下命令,就能把一部电影加载到数据库里:

movie = Movie.new(1)
movie.title = "Doctor Strangelove"
movie.director = "Stanley Kubrick"

Bill看了Bob的代码后说:“重复的代码太多了。数据库里有title字段,代码里有@title成员,还有title方法、title=方法、title字符串常量。如果你会元编程,用很少的代码就可以解决这个问题。”

1.2.2 进入元编程的世界

==未完待续==

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 第1章 元这个字眼
    • 1.1 鬼城与自由市场
      • 1.2 程序员Bob的故事
        • 1.2.1 Bob的第一次尝试
        • 1.2.2 进入元编程的世界
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档