• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    Ruby 魔法 学习笔记之一
    一、向对象显示的发送消息
    我们可以向对象直接发送消息:
    Ruby代码
    复制代码 代码如下:

    class HelloWorld
    def say(name)
    print "Hello, ", name
    end
    end
    hw = HelloWorld.new
    hw.send(:say,"world")

    我们通常使用hw.say("world"),但send可以对private的方法起作用。
    不光如此send可以使程序更加动态,下面我们看看一个例子:
    我们定义了一个类Person,我们希望一个包含Person对象的数组能够按
    照Person的任意成员数据来排序:
    Ruby代码
    复制代码 代码如下:

    class Person
    attr_reader :name,:age,:height
    def initialize(name,age,height)
    @name,@age,@height = name,age,height
    end
    def inspect
    "#@name #@age #@height"
    end
    end
    在ruby中任何一个类都可以随时打开的,这样可以写出像2.days_ago这样优美
    的code,我们打开Array,并定义一个sort_by方法:
    Ruby代码
    class Array
    def sort_by(sysm)
    self.sort{|x,y| x.send(sym) => y.send(sym)}
    end
    end
    我们看看运行结果:
    Ruby代码
    people = []
    people Person.new("Hansel",35,69)
    people Person.new("Gretel",32,64)
    people Person.new("Ted",36,68)
    people Person.new("Alice", 33, 63)
    p1 = people.sort_by(:name)
    p2 = people.sort_by(:age)
    p3 = people.sort_by(:height)
    p p1 # [Alice 33 63, Gretel 32 64, Hansel 35 69, Ted 36 68]
    p p2 # [Gretel 32 64, Alice 33 63, Hansel 35 69, Ted 36 68]
    p p3 # [Alice 33 63, Gretel 32 64, Ted 36 68, Hansel 35 69]
    这个结果是如何得到的呢?
    其实除了send外还有一个地方应该注意attr_reader,attr_reader相当于定义了name,
    age,heigh三个方法,而Array里的sort方法只需要提供一个比较方法:
    x.send(sym) => y.send(sym) 通过send得到person的属性值,然后在使用=>比较
    二、定制一个object
    object
    ruby不仅可以打开一个类,而且可以打开一个对象,给这个对象添加或定制功能,而不影响
    其他对象:
    Ruby代码
    a = "hello"
    b = "goodbye"
    def b.upcase
    gsub(/(.)(.)/)($1.upcase + $2)
    end
    puts a.upcase #HELLO
    puts b.upcase #GoOdBye
    我们发现b.upcase方法被定制成我们自己的了
    如果想给一个对象添加或定制多个功能,我们不想多个def b.method1 def b.method2这么做
    我们可以有更模块化的方式:
    Ruby代码
    b = "goodbye"
    class b
    def upcase # create single method
    gsub(/(.)(.)/) { $1.upcase + $2 }
    end
    def upcase!
    gsub!(/(.)(.)/) { $1.upcase + $2 }
    end
    end
    puts b.upcase # GoOdBye
    puts b # goodbye
    b.upcase!
    puts b # GoOdBye
    这个class被叫做singleton class,因为这个class是针对b这个对象的。
    和设计模式singleton object类似,只会发生一次的东东我们叫singleton.
    self 给你定义的class添加行为
    Ruby代码
    class TheClass
    class self
    def hello
    puts "hello!"
    end
    end
    end
    TheClass.hello #hello!
    self修改了你定义class的class,这是个很有用的技术,他可以定义class级别
    的helper方法,然后在这个class的其他的定义中使用。下面一个列子定义了访问
    函数,我们希望访问的时候把成员数据都转化成string,我们可以通过这个技术来
    定义一个Class-Level的方法accessor_string:
    Ruby代码
    class MyClass
    class self
    def accessor_string(*names)
    names.each do |name|
    class_eval -EOF
    def #{name}
    @#{name}.to_s
    end
    EOF
    end
    end
    end
    def initialize
    @a = [ 1, 2, 3 ]
    @b = Time.now
    end
    accessor_string :a, :b
    end
    o = MyClass.new
    puts o.a # 123
    puts o.b # Fri Nov 21 09:50:51 +0800 2008
    通过extend module给你的对象添加行为,module里面的方法变成了对象里面的
    实例方法:
    Ruby代码
    module Quantifier
    def any?
    self.each { |x| return true if yield x }
    false
    end
    def all?
    self.each { |x| return false if not yield x }
    true
    end
    end
    list = [1, 2, 3, 4, 5]
    list.extend(Quantifier)
    flag1 = list.any? {|x| x > 5 } # false
    flag2 = list.any? {|x| x >= 5 } # true
    flag3 = list.all? {|x| x = 10 } # true
    flag4 = list.all? {|x| x % 2 == 0 } # false
    三、创建一个可参数化的类:
    如果我们要创建很多类,这些类只有类成员的初始值不同,我们很容易想起:
    Ruby代码
    class IntelligentLife # Wrong way to do this!
    @@home_planet = nil
    def IntelligentLife.home_planet
    @@home_planet
    end
    def IntelligentLife.home_planet=(x)
    @@home_planet = x
    end
    #...
    end
    class Terran IntelligentLife
    @@home_planet = "Earth"
    #...
    end
    class Martian IntelligentLife
    @@home_planet = "Mars"
    #...
    end
    这种方式是错误的,实际上Ruby中的类成员不仅在这个类中被所有对象共享,
    实际上会被整个继承体系共享,所以我们调用Terran.home_planet,会输出
    “Mars”,而我们期望的是Earth
    一个可行的方法:
    我们可以通过class_eval在运行时延迟求值来达到目标:
    Ruby代码
    class IntelligentLife
    def IntelligentLife.home_planet
    class_eval("@@home_planet")
    end
    def IntelligentLife.home_planet=(x)
    class_eval("@@home_planet = #{x}")
    end
    #...
    end
    class Terran IntelligentLife
    @@home_planet = "Earth"
    #...
    end
    class Martian IntelligentLife
    @@home_planet = "Mars"
    #...
    end
    puts Terran.home_planet # Earth
    puts Martian.home_planet # Mars
    最好的方法:
    我们不使用类变量,而是使用类实例变量:
    Ruby代码
    class IntelligentLife
    class self
    attr_accessor :home_planet
    end
    #...
    end
    class Terran IntelligentLife
    self.home_planet = "Earth"
    #...
    end
    class Martian IntelligentLife
    self.home_planet = "Mars"
    #...
    end
    puts Terran.home_planet # Earth
    puts Martian.home_planet # Mars
    四、Ruby中的Continuations:
    Continuations恐怕是Ruby中最难理解的概念了,它可以处理非局部的跳转,
    它保存了返回地址和执行的环境,和c中的setjmp和longjump类似,但它保存
    了更多的信息:
    axgle举的曹操的例子很形象,我们拿过来看看:
    来自[http://www.javaeye.com/topic/44271]
    曹操(caocao)被誉为“古代轻功最好的人 ”,是因为“说曹操,曹操到”这句名言。
    在ruby中,曹操的这种轻功被称为callcc.
    Ruby代码
    callcc{|caocao|
    for say in ["曹操","诸葛亮","周瑜"]
    caocao.call if say=="曹操"
    puts say #不会输出,因为曹操已经飞出去了
    end
    }#“曹操”飞到这里来了(跳出了callcc的block,紧跟在这个block后面,继续执行下面的ruby代码)
    puts "到"
    callcc里的caocao是个"延续"(Continuation)对象.这个对象只有名叫“call"的这样一个方法。
    当执行了caocao.call后,caocao就会飞到callcc的块(block)后面,让ruby继续执行其下面的代码。
    我上面给出的是一个从块里头”飞“到块外面的例子;下面是Programming Ruby给出的从代码后面”飞“到代码前面的例子:
    Ruby代码
    arr = [ "Freddie", "Herbie", "Ron", "Max", "Ringo" ]
    callcc{|$cc|}#下面的$cc.call如果被执行,就会飞回到这里(callcc的块之后)。
    puts(message = arr.shift)
    $cc.call unless message =~ /Max/
    例子大多来自The ruby way>>
    您可能感兴趣的文章:
    • Ruby学习笔记之gem 命令详解
    • ruby 学习笔记(2) 类的基本使用
    • ruby 学习笔记(1) 初识语法
    • Ruby学习笔记一
    上一篇:ruby 小脚本搞定CVS服务器更换后checkout下来的工程迁移
    下一篇:Ruby self在不同环境的含义
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    Ruby 魔法 学习笔记之一 Ruby,魔法,学习,笔记,之一,