老实说不是很喜欢去讨论ruby和python的对比,似乎总是把两个语言放在对立的位置上,我觉得没有必要,同样是动态语言,同样是解释型脚本语言,很多特性都是互相影响的,语言本身也在不断进化,我们更应该关注的是编程思想而不是语言本身。

说了一点题外话,之所以要求学ruby,主要就是因为有一本好书想读,就是Paolo Perrotta的《Ruby元编程》,书看了一天,ruby语法学了半天,用irb捣鼓了一晚上,应该说跟python,scala都有很多相近的地方,因为没有接触Lisp,Haskell之类的函数编程语言,因此不好说跟他们怎么样,但是学了python再去学ruby是觉得非常轻松地。

书中星期二中有个问题挑战,就是对DS和Computer类中的函数进行动态生成,好吧,我又犯老毛病了,书看一半,自己先干,在看到define_method方法后用我自己的思路捣鼓了一个解决方案,还没看书中的实例,先把代码弄出来看看,以下就是我的第一个ruby程序:

  1. # 数据源定义,原应为关联数据库,这里只是进行模拟
  2. class DS
  3. parts = 'cpu', 'mouse', 'keyboard' # 临时数组用于批量生成方法
  4. parts.each do |part|
  5. define_method "get_#{part}_info".to_sym do |id| # 生成三种设备的信息函数
  6. "This is #{part} #{id}."
  7. end
  8. define_method "get_#{part}_price".to_sym do |id| # 生成三种设备的价格函数
  9. parts.zip([150, 50, 40]).to_h[part] # 通过zip合并数组转换为哈希结构再索引
  10. end
  11. end
  12. end
  13. # 电脑配件定义
  14. class Computer
  15. def initialize(computer_id, data_source) # 初始化id和数据源
  16. @id = computer_id
  17. @data_source = data_source
  18. end
  19. parts = 'cpu', 'mouse', 'keyboard'
  20. parts.each do |part|
  21. define_method part.to_sym do
  22. info = @data_source.send("get_#{part}_info".to_sym, @id)
  23. price = @data_source.send("get_#{part}_price".to_sym, @id)
  24. result = "#{info} ($#{price})"
  25. return " * #{result}" if price >= 100 # 判断价格是否高于100,加星号显示
  26. result
  27. end
  28. end
  29. end
  30. puts "DS methods: #{DS.instance_methods(false)}"
  31. puts "Computer methods: #{Computer.instance_methods(false)}"
  32.  
  33. ds = DS.new
  34. computer = Computer.new(10, ds)
  35. puts computer.cpu
  36. puts computer.mouse
  37. puts computer.keyboard

然后继续看书,在看到内省的用法的时候觉得比较好,想把我上面的程序修改一下,于是改成了这个样子:

  1. # 电脑配件定义
  2. class Computer
  3. def initialize(computer_id, data_source) # 初始化id和数据源
  4. @id = computer_id
  5. @data_source = data_source
  6. data_source.methods.grep(/^get_(.*)_info$/) {
  7. define_method($1.to_sym) {
  8. info = @data_source.send("get_#{$1}_info", @id)
  9. price = @data_source.send("get_#{$1}_price", @id)
  10. result = "#{info} ($#{price})"
  11. return " * #{result}" if price >= 100 # 判断价格是否高于100,加星号显示
  12. result
  13. }
  14. }
  15. end
  16. end

运行的时候报错了,然后才发现define_method是Class的私有函数,因为属于Class所以不能在实例函数中使用,而因为私有,所以只能隐式调用,如果想这么用只能通过send来进行调用,所以把程序改成了下面这个样子

  1. class Computer
  2. def initialize(computer_id, data_source) # 初始化id和数据源
  3. @id = computer_id
  4. @data_source = data_source
  5. data_source.methods.grep(/^get_(.*)_info$/) {
  6. Computer.send(:define_method, $1) {
  7. info = @data_source.send("get_#{$1}_info", @id)
  8. price = @data_source.send("get_#{$1}_price", @id)
  9. result = "#{info} ($#{price})"
  10. return " * #{result}" if price >= 100 # 判断价格是否高于100,加星号显示
  11. result
  12. }
  13. }
  14. end
  15. end

很不幸,又出问题了,这次出在变量$1未被正确识别,原因是$1是全局变量,而ruby是动态解析的,只有在运行的时候才去获取$1的值,而那个时候它已经编程nil了,因此将全局变量保存为局部变量

  1. # 电脑配件定义
  2. class Computer
  3. def initialize(computer_id, data_source) # 初始化id和数据源
  4. @id = computer_id
  5. @data_source = data_source
  6. data_source.methods.grep(/^get_(.*)_info$/) {
  7. part = $1
  8. Computer.send(:define_method, part) {
  9. info = @data_source.send("get_#{part}_info", @id)
  10. price = @data_source.send("get_#{part}_price", @id)
  11. result = "#{info} ($#{price})"
  12. return " * #{result}" if price >= 100 # 判断价格是否高于100,加星号显示
  13. result
  14. }
  15. }
  16. end
  17. end

其实是有点丑了,不过总要写得跟原文不太一样啦,对于ruby还有不少需要对比和理解,希望看完这本书能好一些

  1.  

第一个ruby程序的更多相关文章

  1. 运行第一个ruby程序

    0x00 安装 首先需要安装一个ruby的环境,ruby分为win.linux.macOS版本.不用系统安装方法略有差异,不在这进行讲解. 0x01 运行第一个ruby程序 我这里是win环境,打开命 ...

  2. [Ruby on Rails系列]3、初试Rails:使用Rails开发第一个Web程序

    本系列前两部分已经介绍了如何配置Ruby on Rails开发环境,现在终于进入正题啦! Part1.开发前的准备 本次的主要任务是开发第一个Rails程序.需要特别指出的是,本次我选用了一个(Paa ...

  3. JFinal教程1——小白的第一个JFinal程序

    为了使小白能够完全的按步骤创建第一个JFinal应用并运行,笔者将以Java界最流行的Eclipse平台为例,搭建出所有基础教程中喜欢的Hello world应用. 1. JFinal简介 2. 小白 ...

  4. Python 开篇及第一个Python程序

    本节内容 python 简单介绍 python 2.x 或者python 3.x python 安装 第一个python程序 一.python简单介绍 python的创始人为吉多.范罗苏姆(Guido ...

  5. 为 Ruby 程序员准备的 Go 入门教程

    这是我翻译的国外博客,如需转载请注明出处和原文链接 那些在Google的大牛们开发出了一种称为Go的牛叉的语言.乍一看,Ruby和Go有点像远房表亲.其实不然,他们那些互为补充的功能却让他们成为一对完 ...

  6. DirectX游戏编程(一):创建一个Direct3D程序

    一.环境 Visual Studio 2012,DirectX SDK (June 2010) 二.准备 1.环境变量(如没有配置请添加) 变量名:DXSDK_DIR 变量值:D:\Software\ ...

  7. 第一个python程序

    一个python程序的两种执行方式: 1.第一种方式是通过python解释器: cmd->python->进入python解释器->编写python代码->回车. 2.第二种方 ...

  8. 编写第一个MapReduce程序—— 统计气温

    摘要:hadoop安装完成后,像学习其他语言一样,要开始写一个“hello world!” ,看了一些学习资料,模仿写了个程序.对于一个C#程序员来说,写个java程序,并调用hadoop的包,并跑在 ...

  9. 1.3 第一个C#程序

    几乎没一门编程语言的第一个程序都叫“你好,世界”,所以先在visual studio 中创建一个Helloworld程序. 各部分的详细内容: Main方法是程序运行的起点,最重要的代码就写在Main ...

随机推荐

  1. Codeforces Round #341 Div.2 D. Rat Kwesh and Cheese

    嗯本来想着直接算出来不就行了吗 然后我想到了200^200^200....... 好吧其实也不难取两次log就行了 然后我第一次写出来log就写残了........... log里面的拆分要仔细啊.. ...

  2. How to create/restore a slave using GTID replication in MySQL 5.6

    MySQL 5.6 is GA! Now we have new things to play with and in my personal opinion the most interesting ...

  3. clientX、pageX、scrollLeft、offsetLeft、clientWidth、screen.width的用法和区别

    一.定义和用法 1.event.clientX:事件对象的水平偏移量: event.clientY:事件对象的垂直偏移量: 2.event.pageX:事件对象加上滚动距离后的水平偏移量: event ...

  4. SQL 用户定义表类型,在存储过程里使用表类型,表参数作参数

    .定义表类型SUTDENTTYPE,包含三个字段,分别对应学生表的NAME,SEX和PHONE.之所以如此创建,我是准备在插入新学生数据的存储过程中,以它为参数.   GO CREATE TYPE S ...

  5. C#遍历指定文件夹中的所有文件和子文件夹

    参考:http://www.cnblogs.com/skylaugh/archive/2012/09/23/2698850.html DirectoryInfo TheFolder=new Direc ...

  6. php自学提升进阶路线

    为了自己对php的系统全面深入的掌握,我通过个人经验,以及搜索网上高手经验,汇总了一份php自我学习路线规划,包括实战演练.学习建议.高手进阶.常见问题和测试总结五块.算是一个系统的学习计划和目标吧. ...

  7. IOS培训还值得么

    文章结构 1培训机构 各方面的评价 培训安排 收获 2 市场 就业 是否饱和 3 姿势 做好的事情 IOS这几年在IT界一直是热门的讨论话题,之前看着拉钩出品的北上广高薪岗位的人员技术流动也主要指向这 ...

  8. JAVA访问权限

      同一个类 同一个包 不同包的子类 不同包的非子类 Private √       Default √ √     Protected √ √ √   Public √ √ √ √

  9. SQL 导出表结构到Excel

    SQL 导出表结构到Excel SELECT 表名 then d.name else '' end, 表说明 then isnull(f.value,'') else '' end, 字段序号 = a ...

  10. 协程、异步IO

    协程,又称微线程,纤程.英文名Coroutine,协程是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器 ...