读书笔记之《七周七语言——理解多种编程范型》Ruby语言学习

正如此书中简介所介绍的一样,作为一个程序员,想要提高自己的编程水平,学习了解各种编程语言是一个很有效的途径。通过吸收各种语言的精髓融入到自己最熟悉的语言代码中去。也许你只是一个Objective-c程序员,但是你同时也想了解如何用Java来开发android程序;也许你只是一个客户端程序员,但是你同时也想了解服务器的开发;也许你永远都用不到Ruby,但是你却想了解Ruby语言的各种特性。。。。。。Keep Moving! 保持不停的学习,不停地探索新技术,这样才能跟上时代的潮流~~~~不管怎样,多了解几门语言总是有好处的。因此,笔者跟大家推荐这本《七周七语言——理解多种编程范型》,并记录自己的学习该书所讲述的语言的一些特性,正所谓“不动笔墨不读书,好记性不如烂笔头”,记好笔记,以备将来翻阅查找。以下全是从原书摘录的笔记:

      Ruby出身于所谓的脚本语言家族,是一种解释型、面向对象、动态类型的语言。解释型,意味着Ruby代码由解释器而非编译器执行。动态类型,意味着类型在运行时而非编译时绑定。从这两方面看,Ruby采取的策略是在灵活性和运行时安全之间寻找平衡点。面向对象,意味着Ruby支持封装、类继承、多态等特性。随着Rails框架崭露头角,Ruby也在2006年开始火起来。Ruby语言的发明者并不担心编程语言的执行效率,而是把精力放在了提高程序员的编程效率上。

     关于Ruby的开发环境的安装,可以在这个链接找到http://www.ruby-lang.org/en/downloads/ 。 作为一个Mac OS X 操作系统的开发者,不必需要再次安装Ruby。因为笔者的Mac OS X 10.8.3系统就默认安装了Ruby。你可以打开终端,输入irb测试是否安装了Ruby。如果没提示任何错误,表示你的操作系统已经安装了Ruby。

   Ruby可以在终端命令行输入irb命令后,直接输入Ruby语句运行,Ctrl-z退出Ruby运行模式。也可以创建一个后缀名为.rb 的hello.rb文件,在该文件输入Ruby语句,然后通过在终端执行 ruby hello.rb命令运行该文件里的ruby代码。

   下面贴出在终端上运行书上代码,通过这些语句就可以学习到Ruby语言的一些特性:

   

bogon:~ ericli$ irb
>> puts 'hello, world'
hello, world
=> nil
>> language = 'Ruby'
=> "Ruby"
>> puts "hello, #{language}"
hello, Ruby
=> nil
>> language='my Ruby'
=> "my Ruby"
>> puts "hello, #{language}"
hello, my Ruby
=> nil

 从代码看出,Ruby是解释执行的;Ruby代码里的变量无需声明,即可直接初始化及赋值;即使你没让Ruby返回任何值,每条Ruby代码都会返回某个值。在Ruby里,单引号的字符串表示将直接解释,双引号包含的字符串则会引发字符串替换。


Ruby的编程模型

>> 4
=> 4
>> 4.clas
NoMethodError: undefined method `clas' for 4:Fixnum
	from (irb):7
>> 4.class
=> Fixnum
>> 4+4
=> 8
>> 4.methods
=> ["%", "odd?", "inspect", "prec_i", "<<", "tap", "div", "&", "clone", ">>", "public_methods", "__send__", "instance_variable_defined?", "equal?", "freeze", "to_sym", "*", "ord", "+", "extend", "next", "send", "round", "methods", "prec_f", "-", "even?", "singleton_method_added", "divmod", "hash", "/", "integer?", "downto", "dup", "object_id", "instance_variables", "|", "eql?", "size", "instance_eval", "truncate", "~", "id", "to_i", "singleton_methods", "modulo", "taint", "zero?", "times", "instance_variable_get", "frozen?", "to_enum", "display", "instance_of?", "^", "to_a", "+@", "-@", "quo", "instance_exec", "type", "**", "upto", "to_f", "<", "step", "protected_methods", "<=>", "between?", "==", "remainder", ">", "===", "to_int", "nonzero?", "pred", "instance_variable_set", "enum_for", "coerce", "respond_to?", "kind_of?", "floor", "succ", ">=", "method", "prec", "to_s", "<=", "fdiv", "class", "private_methods", "=~", "tainted?", "__id__", "abs", "untaint", "nil?", "chr", "id2name", "is_a?", "ceil", "[]"]
 

      在Ruby中,一切皆为对象,就连每个单独的数字也不例外。数字是Fixnum类型的对象 。可以用“.” 符号调用对象具有的任意方法。

Ruby的判断

>> x = 4
=> 4
>> x < 5
=> true
>> x <= 4
=> true
>> x > 4
=> false
>> false.class
=> FalseClass
>> true.class
=> TrueClass


Ruby的判断语句跟其他大部分语言大同小异。

>> x = 4
=> 4
>> puts 'This appears to be false.' unless x == 4
=> nil
>> puts 'This appears to be true.' if x == 4
This appears to be true.
=> nil
>> if x == 4
>>  puts 'This appears to be true.'
>> end
This appears to be true.
=> nil
>> unless x == 4
>>  puts 'This appears to be false.'
>> else 
?>  puts 'This appears to be true.'
>> end
This appears to be true.
=> nil
>> puts 'This appears to be true.' if not true
=> nil
>> puts 'This appears to be true.' if !true
=> nil

在Ruby里,使用if或unless(笔者注:如果不) 时,既可选用块形式 (if condtion, statement, end), 也可选用单行形式(statements if condtion). 

>> x = x + 1 while x < 10
=> nil
>> x
=> 10
>> x = x - 1 until x == 1
=> nil
>> x
=> 1
>> while x < 10 
>>  x = x + 1
>>  puts x
>> end
2
3
4
5
6
7
8
9
10
=> nil
在Ruby中,每种对象都有自己特有的相等概念。数字对象的值相等时,它们相等。
>> puts 'This appears to be true.' if 1
This appears to be true.
=> nil
>> puts 'This appears to be true.' if 'random string'
(irb):39: warning: string literal in condition
This appears to be true.
=> nil
>> puts 'This appears to be true.' if 0
This appears to be true.
=> nil
>> puts 'This appears to be true.' if true
This appears to be true.
=> nil
>> puts 'This appears to be true.' if false
=> nil
>> puts 'This appears to be true.' if nil
=> nil
Ruby中,除了nil和false之外,其他值都代表true。C和C++程序员可得小心了,0也是true!

>> true and false
=> false
>> true or false
=> true
>> false && false
=> false
>> true && this_will_cause_an_error
NameError: undefined local variable or method `this_will_cause_an_error' for main:Object
	from (irb):47
>> false && this_will_not_cause_an_error
=> false
>> true or this_will_not_cause_an_error
=> true
>> true || this_will_not_cause_an_error
=> true
>> true | this_will_cause_an_error
NameError: undefined local variable or method `this_will_cause_an_error' for main:Object
	from (irb):51
>> true | false
=> true

Ruby的逻辑运算符跟C,C++,C#,Java差不多,但稍有不同。and(也可写为&&)是t逻辑与,or(也可写为||)是逻辑或。用这两种运算符验证表达式时,一旦表达式的值已能明确求出,解释器就不再继续执行后面的表达式代码。如果想执行整个表达式的话,可以用&或|进行比较。


鸭子类型

    
>> 4 + 'four'
TypeError: String can't be coerced into Fixnum
	from (irb):53:in `+'
	from (irb):53
>> 4.class
=> Fixnum
>> (4.0).class
=> Float
>> 4 + 4.0
=> 8.0

由以上代码可以知道,Ruby是强类型语言,当发生类型冲突时,你将得到一个错误。Ruby是在运行时而非编译时进行类型检查的。

>> def add_them_up
>>  4 + 'four'
>> end
=> nil
>> add_them_up
TypeError: String can't be coerced into Fixnum
	from (irb):58:in `+'
	from (irb):58:in `add_them_up'
	from (irb):60

关键字def定义一个函数,直到真正尝试执行代码时,Ruby才进行类型检查,这被称作动态类型。静态类型系统的情况下,编译器和工具能捕获更多错误,因此Ruby不会像静态类型语言捕获的错误那么多。这是它的劣势。但Ruby的类型系统也有自己的潜在优势,即多个类不必继承自相同父类,就能以相同方式使用。

>> i = 0
=> 0
>> a = ['100', 100.0]
=> ["100", 100.0]
>> while i < 2
>>  puts a[i].to_i
>>  i = i + 1
>> end
100
100
=> nil

上边代码就是常见的鸭子类型(duck typing)。这数组的第一个元素是string,第二个元素是Float,而把它们转换成整数的代码,都用是to_i。鸭子类型并不在乎其内在类型可能是什么。只要它像鸭子一样走路,像鸭子一样嘎嘎叫,那它就是只鸭子。在这个例子中,to_i就相当于嘎嘎叫。


 定义函数

>> def tell_the_truth
>>   true
>> end
=> nil
和Java、C#不同,你不必为了定义函数而把整个类都构建出来。每个函数都会有返回结果。如果你没有显式指定某个返回值,函数就将返回退出函数前最后处理的表达式的值。函数也是个对象。


数组

>> animals = ['lions','tigers','bears']
=> ["lions", "tigers", "bears"]
>> puts animals
lions
tigers
bears
=> nil
>> animals[0]
=> "lions"
>> animals[10]
=> nil
>> animals[-1]
=> "bears"
>> animals[-2]
=> "tigers"
>> animals[-3]
=> "lions"
>> animals[0...1]
=> ["lions"]
>> animals[0..1]
=> ["lions", "tigers"]
>> (0..1).class
=> Range
>> animals[-1..-2]
=> []
>> animals[0..-1]
=> ["lions", "tigers", "bears"]
>> animals[0..-2]
=> ["lions", "tigers"]
>> animals[-2..-1]
=> ["tigers", "bears"]
       如果访问任何未定义的数组元素,Ruby会直接返回nil。你也能发现一些不会让数组功能更强,但会让它更简便易用的特性。比如:animals[-1]返回倒数第一个元素,animals[-2]返回倒数第二个元素,以此类推。这样为了便于使用而添加的特性就是语法糖。0..1是个Range(区间)对象,表示从0到1(包括0和1)的所有数字。
>> a[0] = 0
NameError: undefined local variable or method `a' for main:Object
	from (irb):19
>> a = []
=> []
>> [1].class
=> Array
>> [1].methods.include?('[]')
=> true
     []实际是Array类的方法,[]和[] = 不过是访问数组的语法糖而已。

>> a[0] = 'zero'
=> "zero"
>> a[1] = 1
=> 1
>> a[2] = ['two', 'things']
=> ["two", "things"]
>> a
=> ["zero", 1, ["two", "things"]]

    从以上代码看出,数组元素不必具有相同类型。

>> a = [[1,2,3],[10,20,30],[40,50,60]]
=> [[1, 2, 3], [10, 20, 30], [40, 50, 60]]
>> a[0][0]
=> 1
>> a[1][2]
=> 30
>> a = [1]
=> [1]
>> a.push(1)
=> [1, 1]
>> a = [1]
=> [1]
>> a.push(2)
=> [1, 2]
>> a.pop
=> 2
>> a.pop
=> 1
     多维数组不过是数组的数组而已。数组拥有极其丰富的API,可将其用作队列、链表、栈、集合,等等。

散列表

>> numbers = {1 => 'one', 2 => 'two'}
=> {1=>"one", 2=>"two"}
>> numbers[1]
=> "one"
>> numbers[2]
=> "two"
>> stuff = {:array => [1,2,3], :string => 'Hi,mom!'}
=> {:array=>[1, 2, 3], :string=>"Hi,mom!"}
>> stuff[:string]
=> "Hi,mom!"
      记住,集合里面就是一个个用来存储对象的桶。在散列表的桶里,每个对象上都贴着一张标签。这标签就是键,而对象就是键所对应的值。散列表就是一串这样的键-值对。散列表的运行机制很像数组,但不一定整数下标,而是可以有任意类型的键。最后那个散列表很有趣,因为在其中首次引入了符号(symbol)。尽管两个同值字符串在物理上不同,但相同的符号却是同一物理对象。

>> 'string'.object_id
=> 2263689000
>> 'string0'.object_id
=> 2263684620
>> :string.object_id
=> 145788
>> :string.object_id
=> 145788

     

>> def tell_the_truth(options={})
>>   if options[:profession] == :lawyer
>>     'it could be believed that is almost certainly not false.'
>>   else
?>     true
>>   end
>> end
=> nil
>> tell_the_truth
=> true
>> tell_the_truth :profession => :lawyer
=> "it could be believed that is almost certainly not false."
>> tell_the_truth ({:profession => :lawyer})
=> "it could be believed that is almost certainly not false."

      需要注意的是,将散列表用作函数的最后一个参数时,大括号可有可无。


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

>> 3.times {puts 'hiya there, kiddo'}
hiya there, kiddo
hiya there, kiddo
hiya there, kiddo
=> 3
>> animals = ['lions and', 'tigers and ','bears', 'oh my']
=> ["lions and", "tigers and ", "bears", "oh my"]
>> animals.each {|a| puts a}
lions and
tigers and 
bears
oh my
=> ["lions and", "tigers and ", "bears", "oh my"]
   上述代码,大括号之间的代码就称作代码块。times是Fixnum类的方法,它会执行n次x,其中x是代码块,n是Fixnum对象的值。可采用{ / }或do/end两种界定代码块的形式,Ruby的一般惯例就是:代码块只占一行时用大括号,代码块占多行时用do/end。

>> class Fixnum
>>  def my_times
>>    i = self
>>    while i > 0
>>      i = i - 1
>>      yield
>>    end
>>   end
>> end
=> nil
>> 3.my_times {puts 'mangy moose'}
mangy moose
mangy moose
mangy moose
=> nil
>> def call_block(&block)
>>   block.call
>> end
=> nil
>> def pass_block(&block)
>>   call_block(&block)
>> end
=> nil
>> pass_block {puts 'Hello, block' }
Hello, block
=> nil
      上述代码打开一个现有类,并向其中添加一个方法。此处添加的方法是my_times,它用yield调用代码块,并循环某个给定次数。代码块还可用作一等参数(first-class parameter),即可将代码块作为参数直接传递给函数(也就相当于将函数作为参数传递给函数),而无需包装在其他结构中传递。 这技术能让你将可执行代码派发给其他方法。参数名前加一个“&”,表示将代码块作为闭包传递给函数。代码块不仅可以用于循环,还可以延迟执行,即等到调用该代码块相关的yield时才会执行。

执行某些条件行为:

in_case_of_emergency do
    use_credit_card
    panic
end

def in_case_of_emergency
    yield if emergency?
end

强制实施某种策略: 

within_a_transaction do
    things_that
    must_happen_together
end
def within_a_transaction
    begin_transaction
    yield
    end_transaction
end

从文件中运行Ruby

    创建一个名为hello .rb的文件,其中包含任意你想执行的Ruby代码,比如:puts 'hello, world' 保存文件到当前文件夹,然后从命令行执行如下命令:ruby hello.rb。即执行文件hello.rb里的Ruby代码。

     集成开发环境虽然功能完善,但用它开发Ruby程序的人很少,大多数人还是乐于使用简便易用的文件编辑器。包括TextMate、vi、emacs在内的众多热门编辑器也都拥有Ruby插件。在你熟练掌握运用文件运行Ruby程序之后,可复用Ruby程序的组件。

    

定义类

    Ruby和Java、C#、C++一样,也有类和对象。Ruby也支持继承,但和C++不同,Ruby中的类只能继承自一个叫做超类的类。

>> 4.class
=> Fixnum
>> 4.class.superclass
=> Integer
>> 4.class.superclass.superclass
=> Numeric
>> 4.class.superclass.superclass.superclass
=> Object
>> 4.class.superclass.superclass.superclass.superclass
    所有的事物,归根结底都继承自Object。一个Class同时也是个Module。

>> 4.class.class
=> Class
>> 4.class.class.superclass
=> Module
>> 4.class.class.superclass.superclass
=> Object
   如此看来,Fixnum派生自Class类。
class Tree
  attr_accessor :children, :node_name
  def initialize(name, children=[])
      @children = children
      @node_name = name
  @end

  def visit_all(&block)
     visit &block
     children.each {|c| c.visit_all &block}
  end

  def visit(&block)
      block.call self
   end
end

ruby_tree = Tree.new( "Ruby", [Tree.new("Reia"), Tree.new("MacRuby")])

puts "Visiting a node"
ruby_tree.visit {|node| puts node.node_name}
puts

puts "visiting entire tree"
ruby_tree.visit_all {|node| puts node.node_name}
  这个类用各种强大特性实现了一棵非常简单的树,

   Ruby的一些惯例和规则:类应以大写字母,并且一半采用骆驼命名法,如CamelClass。实例变量(一个对象有一个值)前必须加上@,而类变量(一个类有一个值)前必须加上@@。实例变量和方法名以小写字母开头,并采用下划线命名法,如underscore_style。常量采用全大写形式,如ALL_CAPS。前面那段代码定义了一个树类。每棵树都有两个实例变量:@children和@node_name。用于逻辑测试的函数和方法一般要加上问号,如if test?。
    attr关键字可用来定义实例变量。它有几种版本,其中最常用的是attr和attr_accessor。attr定义实例变量和访问变量的同名方法,而attr_accessor定义实例变量、访问方法和设置方法。事实上,attr也可以定义设置方法,只需将true作为第二个参数传入即可,如attr:children, true.

    上述代码输出如下:

bogon:Desktop ericli$ ruby hello.rb
Visiting a node
Ruby

visiting entire tree
Ruby
Reia
MacRuby

编写Mixin

面向对象语言利用继承,将行为传播到相似的对象上。但对象若想继承并不相似的多种行为,一方面可通过允许从多个类继承(多继承)而实现,另一方面也可借助于其他解决方案。过往经验表明,多继承不仅复杂,且问题多多。Java采用接口解决这一问题,而Ruby采用的是模块。模块是函数和常量的集合。如果在类中包含了一个模块,那么该模块的行为和常量也会成为类的一部分。

//ruby/to_file.rb
module ToFile
    def filename
       "object_#{self.object_id}.txt"
    end

    def to_f
        File.open(filename, 'w') { |f| f.write(to_s)}
    end
end

class Person
    include ToFile
    attr_accessor :name

    def initialize(name)
        @name = name
    end

    def to_s
        name
    end
end


Person.new('matz').to_f
 这里有件事很有趣:to_s在模块中使用,在类中实现,但定义模块的时候,实现它的类甚至还没有定义!这说明模块和包含它的类之间,是以一种相当隐秘的方式相互作用的。模块依赖的类方法通常不多。在Java中,这种依赖关系是显式的,即类会实现一个约束方法名的接口;而在Ruby中,这依赖关系是隐式的,即通过鸭子类型来实现。这种由Flavors引入,在上至Smalltalk,下至Python的众多语言中采用的编程风格,称作mixin。在这些语言中,带mixin的载体虽未必称作模块,但基本前提是一致的:使用单一继承结合mixin的方式,尽可能合理地将各种行为打包到一起。

上述代码的结果是产生一个类似:object_2250363400.txt的文件,里边写入matz文本。

     

模块、可枚举和集合

        Ruby有两个至关重要的mixin:枚举(enumerable)和比较(comparable)。如果想让类可枚举,必须实现each方法;如果想让类可比较,必须实现<=>操作符。<=>操作符被人们叫做太空船操作符,它比较a、b两操作数,b比较大返回-1,a比较大返回1,相等返回0。为避免方法实现之苦,集合已实现了许多便于使用的可枚举和可比较方法。

>> 'begin' <=> 'end'
=> -1
>> 'same' <=> 'same'
=> 0
>> a = [5,3,4,1]
=> [5, 3, 4, 1]
>> a.sort
=> [1, 3, 4, 5]
>> a.any?{|i| i > 6}
=> false
>> a.any?{|i| i > 4}
=> true
>> a.all? {|i| i > 4 }
=> false
>> a.all? {|i| i > 0 }
=> true
>> a.collect {|i| i * 2}
=> [10, 6, 8, 2]
>> a.select {|i| i % 2 == 0 } # even
=> [4]
>> a.select {|i| i % 2 == 1 } # odd
=> [5, 3, 1]
>> a.max
=> 5
>> a.member?(2)
=> false
      只要集合中任一元素条件为真,any?就返回true;只有集合所有元素条件为真,all?才返回true。由于整数已通过Fixnum类实现了太空船操作符,因此可以调用min和max方法计算最小值和最大值。collect和map方法把函数应用到每个元素上,并返回结果数组。find方法找到一个符合条件的元素,而select和find_all方法均返回所有符合条件的元素,你还可以用inject方法据算列表的和与积:

 

>> a
=> [5, 3, 4, 1]
>> a.inject(0) {|sum, i| sum + i}
=> 13
>> a.inject {|sum, i| sum + i}
=> 13
>> a.inject {|product, i| product *  i}
=> 60
>> a.inject(0) do |sum, i|
?>  puts "sum: #{sum} i: #{i}  sum + i: #{sum + i} "
>>  sum + i
>> end
sum: 0 i: 5  sum + i: 5 
sum: 5 i: 3  sum + i: 8 
sum: 8 i: 4  sum + i: 12 
sum: 12 i: 1  sum + i: 13 
=> 13
 inject方法后跟一个代码块,里面有两个参数和一个表达式。inject会通过第二个参数,把每个列表元素传入代码块,这样代码块就能在每个列表项上执行操作。第一个参数是代码块上一次执行的结果,作为inject方法的参数传入作为代码块第一个参数的初始值(如果不设初始值,inject会使用集合中的第一个值。)

      

开放类

       Ruby的元编程,说白了就是“写能写程序的程序”。Rails核心的ActiveRecord框架,就是用元编程实现了一门简便易用的语言,以便编写连接数据库表的类。

class NilClass
    def blank?
      true
     end
end

class String
    def blank?
      self.size == 0
    end
end

["", "person", nil].each do |element|
    puts element unless element.blank?
end

  以上代码对两个现有的类----NilClass和String添加了一个blank?方法。添加这方法是因为检查字符串状态时,经常想看看字符串是否为空,而字符串既可能呆一个值,也可能是空字符串,还可能是nil。在这里对String和NilClass两个类进行了重定义,利用重定义,甚至能让Ruby完全瘫痪,比如:重定义Class.new方法。对于开放类来说,这里的权衡主要考虑了自由。开放类表示业务领域的度量单位:

class Numeric
    def inches
        self
    end
 

    def feet
        self * 12.inches
    end

    def yards
        self * 3.feet
    end

    def miles
        self * 5280.feet
    end

    def back
        self * -1
    end

    def forward
        self
    end
end


puts 10.miles.back
puts 2.feet.forward



使用method_missing

     Ruby找不到某个方法时会调用一个特殊的调试方法显示诊断信息。

class Roman
    def self.method_missing name, *args
        roman = name.to_s
        roman.gsub!("IV", "IIII")
        roman.gsub!("IX", "VIIII")
        roman.gsub!("XL", "XXXX")
        roman.gsub!("XC", "LXXXX")

        (roman.count("I") +
         roman.count("V") * 5 +
         roman.count("X") * 10 +
         roman.count("L") * 50 +
         roman.count("C") * 100 )
    end
end

puts Roman.X
puts Roman.XC
puts Roman.XII
puts Roman.X

     通过method_missing方法的参数列表,可以获得没找到方法的名称和参数。如果覆盖实现该方法,写的类调试起来比过去困难许多,因为Ruby再也不会告诉你找不到某个方法。因此,使用该方法的时候一定要三思而后行。


  

模块

  模块是Ruby最流行的元编程方式,运用模块能轻松实现def或attr_accessor(提供setter或getter方法访问变量等)关键字的功能,或使用DSL(为某个特定领域量身打造一门语言)扩展类定义,实例如下:

module ActsAsCsv
	def self.included(base)
		base.extend ClassMethods
	end

	module ClassMethods
		def acts_as_csv
			include InstanceMethods
		end
	end

	module InstanceMethods
		def read
			@csv_contents = []
			filename = self.class.to_s.downcase + '.txt'
			file = File.new(filename)
			@headers = file.gets.chomp.split(', ')

			file.each do |row|
				@csv_contents << row.chomp.split(', ')
			end
		end

		attr_accessor : headers, :csv_contents

		def initialize
			read
		end

	end

end

class RubyCsv # 没有继承,你可以自由添加
	include ActsAsCsv
	acts_as_csv
end


m = RubyCsv.new
puts m.headers.inspect
puts m.csv_contents.inspect



一个模块被另一个模块包含,Ruby就会调用该模块的included方法。记住,类也是模块。在ActsAsCsv模块的included方法中扩展了名为base(即RubyCsv类)的目标类。该模块还未RubyCsv类添加了唯一的类方法acts_as_csv方法又打开了RubyCsv类,并在类中包含了所有实例方法。这样,就实现了一个动态对RubyCsv的添加方法的程序,称为会写程序的程序,动态地改变类。

如上述所示,所有元编程技术的有趣的地方在于,程序可以根据它应用时的状态而改变。比如ActiveRecord利用元编程,动态添加与数据库中的列有相同名称的访问器。这样,代码更容易阅读。


 总结

          Ruby的纯面向对象可以让你用一致的方式来处理对象。鸭子类型根据对象可提供的方法,而不是对象的继承层次,实现了更切合实际的多态设计。Ruby的模块和开放类,是程序员能把行为紧密结合到语法上,这大大超越了类中定义的传统方法和实例变量。在脚本开发、Web开发、开发时间上、灵活性、语法,Ruby具有巨大的优势。

         Ruby的弱点是性能低下,在并发编程方面薄弱,类型不安全,难以调试。

       


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值