美文网首页
ruby 语法

ruby 语法

作者: 风___________ | 来源:发表于2018-02-11 21:05 被阅读15次

    1. Here Document: 多行字符串

    print <<ONELINE
    =begin
    注释区
    =end
    内容区
    ONELINE
    

    2. BEGIN 语句

    BEGIN {
      code
    }
    

    声明 code 会在程序运行之前被调用。

    3. END 语句

    END {
      code
    }
    

    声明 code 会在程序的结尾被调用。

    3. 注释

    # 这是注释
    
    =begin
    这是
    多行
    注释
    =end
    

    4. #{ expr } 替换任意 Ruby 表达式的值为一个字符串

    name="Ruby" 
    puts "#{name+",ok"}"
    输出结果为:
    Ruby,ok
    

    5.数组

    数组字面量通过[]中以逗号分隔定义,且支持range定义。

    (1)数组通过[]索引访问
    (2)通过赋值操作插入、删除、替换元素
    (3)通过+,-号进行合并和删除元素,且集合做为新集合出现
    (4)通过<<号向原数据追加元素
    (5)通过*号重复数组元素
    (6)通过|和&符号做并集和交集操作(注意顺序)
    

    6.Ruby 类中的变量

    * 局部变量:局部变量是在方法中定义的变量。局部变量在方法外是不可用的。在后续的章节中,您将看到有关方法的更多细节。局部变量以小写字母或 _ 开始。
    * 实例变量:实例变量可以跨任何特定的实例或对象中的方法使用。这意味着,实例变量可以从对象到对象的改变。实例变量在变量名之前放置符号(@)。
    * 类变量(所有实例对象共用):类变量可以跨不同的对象使用。类变量属于类,且是类的一个属性。类变量在变量名之前放置符号(@@)。
    * 全局变量:类变量不能跨类使用。如果您想要有一个可以跨类使用的变量,您需要定义全局变量。全局变量总是以美元符号($)开始。
    * 常数(Constant): 大写字母开头
    

    7. 自定义方法创建对象

    class Customer
       @@no_of_customers=0
       def initialize(id, name, addr)
          @cust_id=id
          @cust_name=name
          @cust_addr=addr
       end
    end
    cust1=Customer.new("1", "John", "Wisdom Apartments, Ludhiya")
    

    8.Ruby 类中的成员函数

    class Sample
       def function
          statement 1
          statement 2
       end
    end
    
    class Sample
       def hello
          puts "Hello Ruby!"
       end
    end
    # 使用上面的类来创建对象
    object = Sample. new
    object.hello
    
    9.Ruby 伪变量

    它们是特殊的变量,有着局部变量的外观,但行为却像常量。您不能给这些变量赋任何值。

    * self: 当前方法的接收器对象。
    * true: 代表 true 的值。
    * false: 代表 false 的值。
    * nil: 代表 undefined 的值。
    * __FILE__: 当前源文件的名称。
    * __LINE__: 当前行在源文件中的编号。
    

    10.Ruby 比较运算符

    <=> :第一个操作数等于第二个操作数则返回 0,如果第一个操作数大于第二个操作数则返回 1,如果第一个操作数小于第二个操作数则返回 -1
    .eql?:类型和值都需要相等(1 == 1.0 返回 true,但是 1.eql?(1.0) 返回 false)
    equal?:具有相同的对象 id,则返回 true(如果 aObj 是 bObj 的副本,那么 aObj == bObj 返回 true,aObj.equal?bObj 返回 false,但是 aObj.equal?aObj 返回 true。)
    

    11.Ruby 并行赋值

     a, b, c = 10, 20, 30
    // 交换两个值
    a, b  = b, a 
    

    12. 逻辑运算符

    and :&&
    or  :||
    not :!
    

    13. defined? 运算符

    defined? 是一个特殊的运算符,以方法调用的形式来判断传递的表达式是否已定义。它返回表达式的描述字符串,如果表达式未定义则返回 nil。

    defined? variable # 如果 variable 已经初始化,则为 True
    foo = 42
    defined? foo    # => "local-variable"
    defined? $_     # => "global-variable"
    defined? bar    # => nil(未定义)
    defined? method_call # 如果方法已经定义,则为 True
    

    14. .和::运算符

    点运算符:调用类或模块中的方法
    ::(常量解析运算符) :引用类或模块中的常量

    MR_COUNT = 0        # 定义在主 Object 类上的常量
    module Foo
      MR_COUNT = 0
      ::MR_COUNT = 1    # 设置全局计数为 1
      MR_COUNT = 2      # 设置局部计数为 2
    end
    puts MR_COUNT       # 这是全局常量
    puts Foo::MR_COUNT  # 这是 "Foo" 的局部常量
    
    DC56746E-33C6-490A-928E-3669FC2CAA7F.png

    15. 判断

    1. if else 语句
    #!/usr/bin/ruby
    # -*- coding: UTF-8 -*-
     
    x=1
    if x > 2
       puts "x 大于 2"
    elsif x <= 2 and x!=0
       puts "x 是 1"
    else
       puts "无法得知 x 的值"
    end
    
    1. if 修饰符(表示当 if 右边之条件成立时才执行 if 左边的式子)
    $debug=1
    print "debug\n" if $debug
    
    1. unless语句(unless式和 if式作用相反,即如果 conditional 为假,则执行 code。如果 conditional 为真,则执行 else 子句中指定的 code。)
    #!/usr/bin/ruby
    # -*- coding: UTF-8 -*-
     
    x=1
    unless x>2
       puts "x 小于 2"
     else
      puts "x 大于 2"
    end
    
    1. unless修饰符(表示当 unless 右边之条件不成立时才执行 if 左边的式子)
    $var = false
    print "3 -- 这一行输出\n" unless $var
    
    1. Ruby case 语句
    case expr0
    when expr1, expr2
       stmt1
    when expr3, expr4
       stmt2
    else
       stmt3
    end
    

    基本上类似于

    _tmp = expr0
    if expr1 === _tmp || expr2 === _tmp
       stmt1
    elsif expr3 === _tmp || expr4 === _tmp
       stmt2
    else
       stmt3
    end
    
    #!/usr/bin/ruby
    # -*- coding: UTF-8 -*-
     
    $age =  5
    case $age
    when 0 .. 2
        puts "婴儿"
    when 3 .. 6
        puts "小孩"
    when 7 .. 12
        puts "child"
    when 13 .. 18
        puts "少年"
    else
        puts "其他年龄段的"
    end
    输出:小孩
    

    当case的"表达式"部分被省略时,将计算第一个when条件部分为真的表达式。

    case
    when foo then puts 'foo is true'
    when bar then puts 'bar is true'
    when quu then puts 'quu is true'
    end
    # 显示 "bar is true"
    

    16. 循环

    1. while 语句(语法中 do 或 : 可以省略不写。但若要在一行内写出 while 式,则必须以 do 或 : 隔开条件式或程式区块)
    #!/usr/bin/ruby
    # -*- coding: UTF-8 -*-
    
    $i = 0
    $num = 5
    
    while $i < $num  do
       puts("在循环语句中 i = #$i" )
       $i +=1
    end
    
    while $i >= 0
        puts("在循环语句中 i = #$i")
        $i -=1
    end
    
    1. while 修饰符(当 conditional 为真时,执行 code)
    #!/usr/bin/ruby
    # -*- coding: UTF-8 -*-
    
    $i = 0
    $num = 5
    begin
       puts("在循环语句中 i = #$i" )
       $i +=1
    end while $i < $num
    
        
    def name(count)
        puts("name is xiaoming #{count}")
        $i -=1
    end
    name($i) while $i >= 0
    
    结果:
    在循环语句中 i = 0
    在循环语句中 i = 1
    在循环语句中 i = 2
    在循环语句中 i = 3
    在循环语句中 i = 4
    name is xiaoming 5
    name is xiaoming 4
    name is xiaoming 3
    name is xiaoming 2
    name is xiaoming 1
    name is xiaoming 0
    
    1. Ruby until 语句 (当 conditional 为假时,执行 code)
    与while 语句相反
    
    1. until 修饰符 (当 conditional 为 false 时,执行 code)
    与while修饰词相反
    
    1. (1)Ruby for in语句
    #!/usr/bin/ruby
    # -*- coding: UTF-8 -*-
     
    for i in 0..5
       puts "局部变量的值为 #{i}"
    end
    
    1. (2) Ruby each do
    #!/usr/bin/ruby
    # -*- coding: UTF-8 -*-
     
    (0..5).each do |i|
       puts "局部变量的值为 #{i}"
    end
    

    结果:

    局部变量的值为 0
    局部变量的值为 1
    局部变量的值为 2
    局部变量的值为 3
    局部变量的值为 4
    局部变量的值为 5
    
    1. 循环内语句:
      break语句:跳出循环
      next语句: continue 进行下次循环
    #!/usr/bin/ruby
    # -*- coding: UTF-8 -*-
     
    for i in 0..5
       if i > 2 then
          break
       end
       puts "局部变量的值为 #{i}"
    end
    结果:
    局部变量的值为 0
    局部变量的值为 1
    局部变量的值为 2
    

    redo 语句(重新开始最内部循环的该次迭代,不检查循环条件。如果在块内调用,则重新开始 yield 或 call)

    #!/usr/bin/ruby
    # -*- coding: UTF-8 -*-
     
    COUNT = 1
    for i in 0..5
       if (i < 2 && COUNT < 5) then
          puts "局部变量的值为 #{i}"
          COUNT += 1
          redo
       end
    end
    结果:
    局部变量的值为 0
    局部变量的值为 0
    局部变量的值为 0
    局部变量的值为 0
    
    retry 语句(1.9以及之后的版本不支持在循环中使用retry)
    • 如果 retry 出现在 begin 表达式的 rescue 子句中,则从 begin 主体的开头重新开始。
    begin
       do_something   # 抛出的异常
    rescue
       # 处理错误
       retry          # 重新从 begin 开始
    end
    

    17. 方法

    1. 方法基本构成
    # 声明
    def method_name 
       expr..
    end
    def method_name (var1, var2)
       expr..
    end
    
    # 默认值
    def method_name (var1=value1, var2=value2)
       expr..
    end
    
    # 调用
    method_name
    method_name 25, 30
    
    # 返回值  (默认)
    def test
       i = 100
       j = 10
       k = 0
    end
    
    # 返回值  (多个)
    def test
       i = 100
       j = 200
       k = 300
    return i, j, k
    end
    var = test
    puts var
    结果: 
    100
    200
    300
    
    # 可变参数 * 符号
    # *在方法定义时,可将多个参数放入一个数组中
    def sample (*test)
       puts "参数个数为 #{test.length}"
       for i in 0...test.length
          puts "参数值为 #{test[i]}"
       end
    end
    sample "Zara", "6", "F"
    sample "Mac", "36", "M", "MCA"
    # *在方法调用时,可将一个数组拆分成多个参数
    data = [1,5,9]
    big = max(*data)
    # *在方法返回时,可将返回的数组展开給另一个方法调用(带*号的方法调用,别懵)
    max(*polar(x,y))
    
    # 哈希作为有名参数(应用场景:当一个方法多个参数,很难记参数顺序,ruby又不支持为参数值指定参数名,哈希对象做为参数可以得到近似的功能)
    # 为了更好的支持这个风格,当哈希作为最后一个参数(或者其后只有一个&打头的代码块参数)时候可以省略{}
    def sequence(args)
      n = args[:n] || 0
      m = args[:m] || 1
    end
    sequence(:m=>3, :n=>5)
    # 关键字参数的方法定义
    # 指定参数的默认值
    def area2(x:0, y:0, z:0)
    xy = x * y
    yz = y * z
    zx = z *x
    (xy+yz+zx) * 2 
    end
    # 调用的时候指定参数名
    area2(x: 2, y: 3, z: 4)
    area2(z: 4, y: 3, x: 2) 
    # 可以用 散列作为实参
    args = {x: 2, y: 3, z: 4}
    area2(args)
    
    1. 类方法 实例方法 单键方法
    # 类方法实际就是一种单键方法
    # ruby实现上把Fixnum和symbol的值看作立即值而非对象引用,因此无法定义单键方法,为了维持一致性,numeric对象也不能
    # 声明
    class Accounts
       def reading_charge
           puts "实例方法"
       end
       def Accounts.return_date
           puts "类方法"
       end
       o = "message"
       def o.printme
          p "单键方法"
       end
    end
    
    # 调用
    Accounts.return_date
    Accounts.new.reading_charge
    o.printme
    # 结果
    类方法
    实例方法
    单键方法
    
    1. 方法命名
    • 小写开头下划线连接
    • 方法名可以!?= 结尾
    • ? 结尾一般用在返回一个能回答调用者给出问题的值。eg:empty? black? nonzero?
    • ! 结尾的方法要小心调用:代表此方法是可变的方法,会改变对象的内部状态 eg: 数组的sort!
    • = 结尾的方法代表赋值方法
    • 许多ruby操作符是用定义在类中的方法实现的,所以许多操作符可以用方法重载 eg: + * 甚至[] (仅有的例外一元加和一元减用+@和-@定义)

    18. alias 语句 和 undef 语句

    • alias 语句用于为方法或全局变量起别名
    • alias 语句更重要的是为一个存在的方法增加新的功能
    alias 方法名 方法名
    alias 全局变量 全局变量
    
    # eg:
    alias foo bar
    alias $MATCH $&
    
    def hello
      p "hello word"
    end
    alias original_hello hello
    def hello
      p "change hello"
      original_hello
      p "add other"
    end
    
    • undef 语句用于取消方法定义
    • undef 不能出现在方法主体内
    # 下面的实例取消名为 bar的方法定义
    undef bar
    

    19. 块(block) 和 yield 语句

    • 代码块的作用域:块中能访问到方法内的局部变量,块中的局部变量仅存在于块中
    • 块由大量的代码组成。
    • 您需要给块取个名称。
    • 块中的代码总是包含在大括号 {} 或do end内。
    • 块总是从与其具有相同名称的函数调用。这意味着如果您的块名称为 test,那么您要* 使用函数 test 来调用这个块。
    • 您可以使用 yield 语句来调用块。
    1. 第一种方式
    # 无参:
    def nameSay
        puts "name is "
        yield
    end
    
    # 可以用花括号和do end作为代码的分节符
    # 惯例:代码块只有一行用{} 多行用do end
    # 起始的花括号或do关键字必须和方法调用在同一行
    nameSay{ puts "xiaoming" }
    结果
    name is 
    xiaoming
    
    nameSay do
    puts "xiaoming"
    puts "xiaohong"
    end 
    结果
    name is 
    xiaoming
    xiaohong
    
    # 参数
    def test
       yield 5
       puts "在 test 方法内"
       yield 100
    end
    test {|i| puts "你在块 #{i} 内"}
    结果
    你在块 5 内
    在 test 方法内
    你在块 100 内
    
    1. 第二种方式
    def test(&block)
       block.call 1000
    end
    test {|i| puts "Hello World!#{i}"}
    结果
    Hello World!1000
    
    # 代码块默认最后一行最为返回值
    # 如果希望代码块有多个返回值,或者结束当前进行下次,请用next 关键字
    # 不要用return return关键字会导致包含代码块的那个方法返回
    array.collect do |x|
      next 0 if x == nil
      next x, x*x
    end
    # next上述使用并不多见,常用以下这种
    array.collect do |x|
      if x == nil
        0
      else
        [x,x**2]
      end
    end
    
    1. 代码块中声明一个与外部同名的块内局部变量的语法(分号)
    # 下面是两个参数和三个块级局部变量的代码块
    has.each {|key,value;i,j,k| ...}
    
    1. 代码块传递实参
    # 迭代器在传递实参的时候把全局变量变成了:one和实例变量变成了1
    {:one=>1}.each_pair {|$key,@value| ...}
    
    # 代码块多个实参
    def two
      yield 1,2,3,4,5,6
    end
    two{|x| p x}  # => in ruby 1.8 :warns and print   [1,2,3,4,5,6]       
    two{|x| p x}  # => in ruby 1.9 :no warns and print     1
    two{|*x| p x} # => in everyone version :no warns and print   [1,2,3,4,5,6]
    two{|x,| p x} # => in everyone version :no warns and print   1
    
    # yield语句和方法一样允许不带花括号的哈希作为最后一个实参(当yield最后一个实参是哈希的时候可以省略花括号)
    def hashiter; yield :a=>1, :b=>2; end
    
    # ruby1.9+ 代码块的最后一个行参可以(和方法一样)具有&前置
    printer = lambda {|&b| puts b.call}
    printer.call {"hi"}
    

    代码块和方法行参的区别是:代码块参数不允许有默认值

    [1,2,3].each {|x,y=10| p x*y} # => syntaxError
    # in ruby 1.9 新语法可以有默认值,改写如下
    [1,2,3].each &->(x,y=10){p x*y} # => 102030
    
    1. BEGIN 和 END 块
    BEGIN { 
      # BEGIN 代码块
      puts "BEGIN 代码块"
    } 
     
    END { 
      # END 代码块
      puts "END 代码块"
    }
      # MAIN 代码块
    puts "MAIN 代码块"
    
    结果
    BEGIN 代码块
    MAIN 代码块
    END 代码块
    

    20. 模块(Module):函数追加,共享函数~

    Mixins (Ruby 不直接支持多重继承,这个牛逼了~)
    module A
       def a1
       end
       def a2
       end
    end
    module B
       def b1
       end
       def b2
       end
    end
     
    class Sample
    include A
    include B
       def s1
       end
    end
     
    samp=Sample.new
    samp.a1
    samp.a2
    samp.b1
    samp.b2
    samp.s1
    
    module Trig
       PI = 3.141592654
       def Trig.sin(x)
       # ..
       end
       def Trig.cos(x)
       # ..
       end
    end
    
    module Moral
       VERY_BAD = 0
       BAD = 1
       def Moral.sin(badness)
       # ...
       end
    end
    
    require 语句:类似于 C 和 C++ 中的 include 语句以及 Java 中的 import 语句
    $LOAD_PATH << '.'
    
    require 'trig.rb'
    require 'moral'
     
    y = Trig.sin(Trig::PI/4)
    wrongdoing = Moral.sin(Moral::VERY_BAD)
    
    注释:
    1.  $LOAD_PATH << '.' 让 Ruby 知道必须在当前目录中搜索被引用的文件。如果您不想使用 $LOAD_PATH,那么您可以使用 require_relative 来从一个相对目录引用文件
    2. 文件包含相同的函数名称。所以,这会在引用调用程序时导致代码模糊,但是模块避免了这种代码模糊,而且我们可以使用模块的名称调用适当的函数
    
    extent 语句 (类中嵌入模块的类方法)
    class  Student
      include B
      extend A
    end
    
    include语句(类中嵌入模块的实例方法)
    # 下面的模块写在 support.rb 文件中
    module Week
       FIRST_DAY = "Sunday"
       def Week.weeks_in_month
          puts "You have four weeks in a month"
       end
       def Week.weeks_in_year
          puts "You have 52 weeks in a year"
       end
    end
    
    # include 使用
    #!/usr/bin/ruby
    $LOAD_PATH << '.'
    require "support"
    
    class Decade
    include Week
       no_of_yrs=10
       def no_of_months
          puts Week::FIRST_DAY
          number=10*12
          puts number
       end
    end
    d1=Decade.new
    puts Week::FIRST_DAY
    Week.weeks_in_month
    Week.weeks_in_year
    d1.no_of_months
    # 结果
    Sunday
    You have four weeks in a month
    You have 52 weeks in a year
    Sunday
    120
    

    21.语句和控制

    • return: 使外围方法返回至调用者,代码块内无论嵌套多深的代码块,他总使得外围方法返回
    • break: 不会使词法意义上的外围方法返回,break只能出现在循环或者代码块中,break 可以带返回值
    • next: 等价其他语言的continue
    • redo: 重新开始一个循环或者迭代的当前迭代,与next的区别,next将控制权传递给下一循环,redo控制权传递给循环或代码块当前迭代的开头,相当于额外进行了一次本循环
    • retry: redo的加强版~,会使得代码块以及迭代器方法推出然后重新开始迭代,ruby 1.9 已经将其移除了,使用要小心无限循环
    • throw/catch: catch不需要和throw处在一个方法内,throw可以跳出当前的循环和代码块,且可以对外跳出任意级数使其与catch一同定义的代码块退出

    22. 异常

    # raise函数抛出异常
    raise Exception.new('not_found_article') if art.nil?
    raise Exception.new('try_to_modify_others_article?') unless art.user_id == User.current.id
    

    异常处理的三个从句:

    • rescue : 处理异常
    • else :在不执行rescue情况下会执行else
    • ensure :无论有无异常都会执行(类似oc中的@finlly)
    def method_name(x)
      rescue
          ...
      else
          ...
      ensure
          ...
    end
    
    # rescue 处理异常 (本事不是一个语句 而是一个可以附加到其他语言上的从句)
    def risky
      begin
        10.times do
            explode
          end
      rescue TypeError
        p $!
      end
      "hello"
    end
    
    rescue
    作为语句修饰符 rescue
    y = factorial(x) rescue x*2
    # 相当于 上述代码好处不需要begin end 关键字
    y = begin 
              factorial(x) 
          rescue
              x*2
          end  
    

    23. ruby 线程 纤程 连续体(连续体没研究)

    # 最简单的线程使用 Thread
    f = "file://name"
    Thread.new {File.read(f)}
    
    # 纤程fiber
    # resume 调用时将会执行block,直到结束或者遇到Fiber.yield类方法,将控制权交给调用者且保存状态,再次执行resume时将继续上次状态继续运行
    # 通过resume和yield方法的实参和返回值可以使得纤程与调用者交换数据
    2.3.4 :044 > f = Fiber.new{
    2.3.4 :045 >    p "Fiber says Hello"
    2.3.4 :046?>   Fiber.yield
    2.3.4 :047?>   p "goodbye"
    2.3.4 :048?>   }
     => #<Fiber:0x007f8e62168648> 
    2.3.4 :050 > f.resume
    "Fiber says Hello"
     => nil 
    2.3.4 :051 > f.resume
    "goodbye"
    
    # 纤程的应用实现生成器:每次调用返回斐波那数列的下一个数
    2.3.4 :055 >   def feibona(x,y)
    2.3.4 :056?>   Fiber.new do
    2.3.4 :057 >       x_c = x
    2.3.4 :058?>     y_c = y
    2.3.4 :059?>     loop do
    2.3.4 :060 >         Fiber.yield y_c
    2.3.4 :061?>         x_c,y_c = y_c,x_c+y_c
    2.3.4 :062?>       end
    2.3.4 :063?>     end
    2.3.4 :064?>   end
    2.3.4 :066 > g = feibona 0,1
     => #<Fiber:0x007f8e6204d560> 
    2.3.4 :067 > 10.times{p g.resume}
    
    # 封装版本的
    class FibonaGenerator
      def initialize
        @x,@y = 0,1
        @fiber = Fiber.new do
          loop do
            @x,@y = @y,@x+@y
            fiber.yield @x
          end
        end
      end
    def next
      @fiber.resume
    end
    def rewind
      @x,@y = 0,1
    end
    end
    # 使用
    g = FibonaGenerator.new
    10.times{print g.next} 
    g.rewind # 重置
    
    # 第三方库 fiber:可以实现多个fiber之间传递控制权
    # transfer :fiber之间穿梭
    # alive:检测一个fiber是否在运行
    # current:返回当前掌握控制权的fiber
    require 'fiber'
    f=g=nil
    f = Fiber.new{|x| 
      p "f1 is #{x}"
      x = g.transfer(x+1)
      p "f2 is #{x}"
      x = g.transfer(x+1)
      p "f3 is #{x}"
      x+1
    }
    g = Fiber.new{|x|
      p "g1 is #{x}"
      x = f.transfer(x+1)
      p "g2 is #{x}"
      x = f.transfer(x+1)
    }
    p f.transfer(1)
    ==begin
     f1:1
     g1:2
     f2:3
     g2:4
     f3:5
     6
    ==end
    

    相关文章

      网友评论

          本文标题:ruby 语法

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