美文网首页Ruby、Rails知识
七周七语言之Ruby笔记

七周七语言之Ruby笔记

作者: alighters | 来源:发表于2016-08-18 23:11 被阅读134次

    简史

    Ruby 出身于所谓的脚本语言家族,是一种解释型、面向对象、动态类型的语言 。解释型,意味着Ruby代码由解释器而非编译器执行。动态类型,意味着类型在运行时而非编译时绑定。

    面向对象,意味着Ruby支持封装(把数据和行为一起打包)、类继承(用一棵类树来组织对象类型)、多态(对象可表现为多种形式)等特性。

    尽管从执行速度上说,Ruby谈不上有多高效,但它却能让程序员的编程效率大幅提高。

    作者谈到他喜欢Ruby寓编程于乐的方式。说到某个具体的技术点,最喜欢的是“代码块”(block)。代码块即是一种易于控制的高阶函数,也为DSL(Domain-Specific Language,领域特定语言)及其他特性的实现提供了极大的灵活性。

    Ruby的编程模型

    大部分的面向对象语言,都带有过程式余元要素,比如数字4在Java中就不是对象。另外某些函数式语言(如Scala)还加入了一些面向对象思想。

    也有很多其他编程模型。基于栈的语言(如PostScript或Forth),使用一个或多个栈作为该语言的核心特征。基于逻辑的语言(如Prolog),是以规则(rule)为中心建立起来的。原型语言(如Io、Lua和Self)用对象而不用类来作为定义对象甚至继承的基础。

    而Ruby是一门纯面向对象语言,一切皆对象。

    鸭子类型

    鸭子类型并不在乎其内在类型可能是什么。只要它像鸭子一样走路,像鸭子一样嘎嘎叫,那它就是只鸭子。

    散列表

    符号(symbol)是前面带有冒号的标识符,类似于:symbol的形式,可用作散列表的key。它在给事物命名时非常好用。尽管两个同值字符串在物理上不同,但相同的符号却是统一物理对象。我们可通过多次获取相同的符号对象标识符来证实这一点,像下面这样:

    >> 'string'.object_id
    => 3092010
    
    >> 'string'.object_id
    => 3089690
    
    >> :string.object_id
    => 69618 
    
    >> :string.object_id
    => 69618 
    

    数组元素、散列表键、散列表值几乎可以任选类型,那么我们就能用Ruby构造出极为精妙的数据结构。

    代码块和yield

    代码块是没有名字的函数。它可以作为参数传递给函数或方法。

    Ruby的一般惯例是:代码块只占一行时用大括号,代码块占多行时用do/end。

    看看以下自定义实现的times方法:

    class Fixnum 
      def my_times
        i = self
        while i > 0
           i = i - 1
           yield
       end
     end
    

    代码块还可用作一等参数(first-class parameter),看看下面的例子:

    def call_block(&block)
      block.call
    end
    
    def pass_block(&block)
      call_block(&block) 
    end
    
    pass_block {puts 'Hello, block'}
    

    这技术能让你把可执行代码派发给其他方法。

    定义类

    所有的事物,归根结底都继承自Object。一个Class同时也是一个Module。

    Class的实例将作为对象的模板。Fixnum是Class的一个实例,而4又是Fixnum的一个实例。每一个类同时也是一个对象。

    Fixnum派生自Class类。从这里开始,你可能会有些费解。Class继承自Module,Module又继承自Object,说到底,Ruby中的一切事物都有一个共同祖先——Object。

    类应以大写字母开头,并且一般采用骆驼命名法,如CamelCase。实例变量(一个对象有一个值)前必须加上@,而类变量(一个类有一个值)前必须加上@@。

    attr关键字可用来定义实例变量。它有几种版本,其中最常用的版本是attr和attr_accessor。attr定义实例变量和访问变量的同名方法,而attr_accessor定义实例变量、访问方法和设置方法。

    编写Mixin

    过往经验表明,多继承不仅复杂,且问题多多。Java采用接口解决这一问题,而Ruby采用的是模块。模块是函数和常量的集合。如果在类中包含了一个模块,那么该模块的行为和常量也会成为类的一部分。

    模块与包含它的类之间,是以一种相当隐秘的方式相互作用的。模块依赖的类方法通常不多。在Java中,这种依赖关系是显式的,即类会实现一个约束方法名的接口;而在Ruby中,这依赖关系是隐式的,即通过鸭子类型来实现。

    学会利用简明的单继承,先定义类的主要部分,然后用模块添加额外功能。

    这种由Flavors引入,在上至Smalltalk,下至Python的众多语言中采用的编程风格,就称作mixin。在这些语言中,带mixin的载体虽未必称作模块,但基本前提是一致的:使用单一继承结合mixin的方式,尽可能合理地把各种行为打包到一起。

    模块、可枚举和集合

    Ruby有两个至关重要的mixin:枚举(enumerable)和比较(comparable)。如果想让类可枚举,必须实现each方法;如果想让类可比较,必须实现<=>操作符。

    collect和map方法把函数应用到每个元素上,并返回结果数组。find方法找到一个符合条件的元素,而select和find_all方法均返回所有符合条件的元素。你还可以用inject方法计算列表的和与积。

    inject方法看似复杂,实则不然。它后面跟一个代码块,里面有两个参数和一个表达式。inject会通过第二个参数,把每个列表元素传入代码块,这样代码块就能在每个列表项上执行操作。第一个参数是代码块上一次执行的结果。

    重大特征

    元编程,说白了就是“写能写程序的程序”。Rails核心的ActiveRecord框架,就用元编程实现了一门简便易用的语言,以便编写连接数据库表的类。如果给department(部门)写个ActiveRecord类,写出来可能像下面这样:

    class Department < ActiveRecord::Base
        has_many :employees
        has_one :manager
    end
    

    1.打开类

    你和“开放类”曾有过一面之交,它可以随时改变任何类的定义,常用于给类添加行为。

    利用这种重定义,我们甚至能让Ruby完全瘫痪,比如重定义Class.new方法。

    对于开放类来说,这里的权衡主要考虑了自由。有这种随时重定义任何类或对象的自由,我们就能写出极为通俗易懂的代码。不过你也要明白,自由越大、能力越强,担负的责任也越重。

    2.使用method_missing

    Ruby找不到某个方法时,会调用一个特殊的调试方法显示诊断信息。该特性不仅让Ruby更易于调试,有时还能实现一些不易想到的有趣行为。只需要覆盖method_missing方法,我们就可以实现这些行为。

    3.模块

    说到Ruby最流行的元编程方式,非模块莫属。尽在模块中写上寥寥数行代码,就可以实现 def 或 attr_accessor 关键字的功能。其中一种技术是设计自己的DSL(domain-specific language,领域特定语言),再用DSL定义自己的类。该DSL在模块中定义各种方法,这些方法添加了对类进行管理所必需的全部方法和常量。可以通过宏(macro)的模块方法添加类行为。宏经常根据环境变化改变类行为。

    只要某个模块被另一模块包含,Ruby就会调用该模块的included方法。记住,类也是模块。

    所有这些元编程技术的有趣之处在于,程序可以根据它应用时的状态而改变。ActiveRecord利用元编程,动态添加与数据库中的列有相同名称的访问器。有些XML框架如builder,可允许用户通过method_missing方法定义自定义标签,以提供更加美观的语法。当代码的语法变得更美观,阅读代码的读者也就不必在语法问题上大伤脑筋,从而能更好地理解代码本身表达的意图。这正是Ruby的威力所在。

    总结

    一些最出色的Ruby框架,如Builder和ActiveRecord,都会为了改善可读性而特别依赖元编程。通过开放类技术编写的鸭子类型接口(为String对象和nil提供了blank?方法),会大大减少了用其他语言完成类似任务可能出现的大量杂乱无章的代码。另外利用method_missing方法可以写出漂亮的罗马数字代码。

    不足

    ** 性能:** 1.9版甚至比过去快了10倍之多。Evan Phoenix写的新虚拟机Rubinius初步实现了用即时编译器(just-in-time compiler)编译Ruby代码。用这种方法观察大段代码在企业中应用的模式,以判断哪些代码可能多次使用。这对于Ruby的运行方式来说相当合适,但是Matz也十分清楚,他写Ruby是为了改善程序员的体验,而不是优化语言的性能。Ruby正是凭借它的许多特性(比如开放类、鸭子类型、method_missing等),击败了可编译并由此提升性能的语言。

    ** 并发问题:** 面向对象编程有一个重大弱点:该编程模型成立的一切前提条件,都建立在一种思想(围绕状态包装一系列行为)的基础之上,但通常,状态是会发生改变的。于是,程序中存在并发时,这种编程策略就会引发严重问题。最好的情况下,Ruby会产生大量的资源竞争;最坏的情况下,面向对象语言几乎无法在并发环境下调试程序,也无法可靠地测试程序。

    相关文章

      网友评论

        本文标题:七周七语言之Ruby笔记

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