Ruby基础教程(四)——运算符、异常、块

运算符

  1. 运算符
运算符 说明
+
-
*
/
%
** 求幂
==
=== ???case..when语句中使用,一般不在外部使用???
!=
>
<
>=
<=
<=> 返回参数比较的结果,0/1/-1
=
+=
-=
*=
/=
%=
**=
&
|
^ 异或
~ 取反
>>
<<
&& ???同and???
|| ???同or???
! ???同not???
and
or
not
? :
. Array.size
.. 1..5 ==> 1-5
1…5 ==> 1-4
:: Net::HTTP

2. 一些判断的方法
eql?——判断值对象是否相等
equal?——判断对象ID是否相等
defined?

```
#判断变量是否定义
foo = 42
defined? foo    # => "local-variable"
defined? $_     # => "global-variable"

#判断方法是否定义
defined? puts        # => "method"
defined? puts(bar)   # => nil (bar is not defined here)
defined? unpack      # => nil (not defined here)

#判断块是否被传递
defined? yield    # => "yield" (if there is a block passed)
defined? yield    # => nil (if there is no block)
```

3. 运算符重载

  • 不能被重载的运算符

    = .. … ?: :: && || not and or

  • 重载二元运算符

    • 重载二元运算符时,常把参数名定义为other

    • 在方法内创建当前类的对象时,不能直接写类名,因为直接写类名会创建确定的类,而用self.class,创建的类就是实际调用new方法时的类

    class Point
        attr_reader :x, :y
    
        def initialize( x = 0, y = 0 )
            @x, @y = x, y
        end
    
        def inspect
            "#{x}, #{y}"
        end
    
        def +(other)
            self.class.new( x + other.x, y + other.y )
        end
    
        def -(other)
            self.class.new( x - other.x, y - other.y )
        end
    end
    
    point0 = Point.new(3, 6)
    point1 = Point.new(1, 8)
    
    p point0            #==> 3, 6
    p point1            #==> 1, 8
    p point0 + point1   #==> 4, 14
    p point0 - point1   #==> 2, -2

    作为程序运行结果输出,用to_s方法;内部调试时,用inspect方法

  • 重载一元运算符

    • 可以重载的一元运算符:+ - ~ !

    • 重载时,以+@ -@ ~@ !@命名

    class Test
        def -@
            self.class.new(-x, -y)
        end
    end
  • 重载下标方法

    class Point
        def [](index)
            case index
            when 0
                x
            when 1
                y
            else
                p "Error"
            end
        end
    
        def []=(index, val)
            case index
            when 0
                self.x = val
            when 1
                self.y = val
            else
                p "Error"
            end
        end
    end
    
    point = Point.new(3, 6)
    p point[0]        #==> 3
    p point[1] = 2    #==> 2
    p point[1]        #==> 2
    p point[2]        #==> 错误

异常

  • 异常处理

    begin
        可能会发生异常的处理
    rescue => ex   #异常对象
        发生异常时的处理
    ensure
        不管是否发生异常都希望之星的处理
    end
    • 发生异常时被自动赋值的变量

      $!——最后发生的异常(异常对象)

      $@——最后发生异常的位置信息

    • 异常对象的方法

      class——异常的种类

      message——异常消息

      backtrace——$@ == $!.backtrace

    • 简写

    
    # 如果整个方法或类都捕获异常的话,可以省略begin~end,直接写rescue或ensure部分
    
    def foo
        process
    rescue
        异常处理
    ensure
        后处理
    end
  • 重试

begin
    process
rescue
    sleep 10
    retry    #==>  发生异常时,重复执行process
end
  • rescue修饰符

    表达式1 rescue 表达式2

    如果表达式1发生异常,表达式2的值会成为整体表达式的值,等价于

    begin
        表达式1
    rescue
        表达式2
    end
  • 指定需要捕获的异常

    用多个rescue分开处理

    begin
        process1
    rescue Exception1, Exception2 => 变量1
        process2
    rescue Exception3, Exception4 => 变量3
        process3
    rescue => 变量3
        process4
    end
  • 异常类

    Exception
    |
    |==========SystemExit
    |==========NoMemoryError
    |==========SignalException
    |==========ScriptError
    |==========|==========LoadError
    |==========|==========SyntaxError
    |==========|==========NotImplementedError
    |==========StandardError
    |==========|==========RuntimeError
    |==========|==========SecurityError
    |==========|==========NameError
    |==========|==========|==========NoMethodError
    |==========|==========IOError
    |==========|==========|==========EOFError
    |==========|==========SystemCallError
    |==========|==========|===============Errno:EPERM
    |==========|==========|===============Errno:ENOENT

    • 程序默认捕获StandardError类及其子类的异常

    • 自己定义异常时,一般先定义继承StandardError的新类,然后再继承这个类

      MyError = Class.new(StandardError)
      MyError1 = Class.new(MyError)
      MyError2 = Class.new(MyError)
      MyError3 = Class.new(MyError)
      MyError4 = Class.new(MyError)
      
      begin
          process
      rescue
          process1
      end
  • 主动抛出异常

    raise 方法——主动抛出异常

    • raise message

      抛出RunTimeError异常,把message传给异常对象

    • raise 异常类

      抛出指定的异常

    • raise 异常类,message

      抛出指定的异常, 把message传给异常对象

    • raise

      在rescue外时,抛出RunTimeError

      在rescue中时,再次抛出最后一次发生的异常

  • 块就是在调用方法时,能与参数一起传递的多个处理的集合

  • 块的使用

    • 循环

      实现了循环处理的方法,称为迭代器

      sum = 0
      hash = { "a"=>1, "b"=>2, "c"=>3, "d"=>4 }
      
      hash.each do |pair|
          sum += pair[1]  #==> 用pair表示散列,pair[0] = key, pair[1] = value
      end
      
      hash.each do |key, value|
          sum += value
      end
    • 隐藏常规处理

      
      #确保后处理被执行
      
      File.open("XXX") do |file|
          file.each_line do |line|
              print line
          end
      end
      
      #如果open失败,open方法会自动调用close,不用手动close
      
    • 替换部分算法

      array = ["Ruby", "Perl", "Python", "PHP"]
      sorted = array.sort
      p sorted   #==> ["PHP", "Perl", "Python", "Ruby"]
      
      array = ["Ruby", "Perl", "Python", "PHP"]
      sorted = array.sort{ |a, b| a <=> b } #==> 将负责比较的块变量传递给sort方法
      p sorted   #==> ["PHP", "Perl", "Python", "Ruby"]
      ary = %w(
          Ruby is a open source programming language with a focus on simplicity and productivity. It has an elegant syntax that is natural to read and easy to write
      )
      
      call_num = 0
      sorted = ary.sort do | a, b |
          call_num += 1
          a.length <=> b.length
      end
      
      p "排序结果 #{sorted}"
      p "数组的元素数量 #{ary.length}"   #==> "数组的元素数量 28"
      p "调用块的次数 #{call_num}"       #==> "调用块的次数 91"
      
      
      #用sort_by方法将每个元素在块中调用一次,然后根据结果做排序处理
      
      sorted = ary.sort_by{ |item| item.length }
      p sorted
  • 定义带块的方法

    • 执行块

      def myloop
          while true
              yield
          end
      end
    • 传递块参数,获取块的值

      def total(from, to)
          result = 0
          from.upto(to) do | num |
              if block_given?    #==> 判断是否有块参数传递进来
                  result += yield(num)
              else
                  result += num
              end
          end
          return result
      end
      
      p total(1, 10)                   #==> 55
      p total(1, 10){ |num| num ** 2}  #==> 385 
      def block_args_test
          yield()
          yield(1)
          yield(1, 2, 3)
      end
      
      p "通过|a|接收块变量"
      block_args_test do |a|
          p [a]
      end
      
      #==> [nil]
      
      
      #==> [1]
      
      
      #==> [1]
      
      
      p "通过|a, b, c|接收块变量"
      block_args_test do |a, b, c|
          p [a, b, c]
      end
      
      #==> [nil, nil, nil]
      
      
      #==> [1, nil, nil]
      
      
      #==> [1, 2, 3]
      
      
      p "通过|a|接收块变量"
      block_args_test do |*a|
          p [a]
      end
      
      #==> [[]]
      
      
      #==> [[1]]
      
      
      #==> [[1, 2, 3]]
      
    • 控制块的执行

      n = total(1, 10) do |num|
          if num == 5
              break
          end
          num
      end
      p n #==>nil
      
      #在块中使用break,程序马上返回到调用块的地方,之前的结果会被忽略掉
      
      
      n = total(1, 10) do |num|
          if num % 2 != 0
              next 0
          end
          num
      end
    • 将块封装为对象

      hello = Proc.new do |name|
          p "Hello, #{name}"
      end
      
      hello.call("David")
      hello.call("Wang")
      
      #将块从一个方法传递给另一个方法时,会通过变量将块作为Proc对象接收
      
      
      #在方法定义时,如果末尾的参数使用“&参数名”的形式,则自动把块封装为Proc对象
      
      
      #Proc参数一定要在所有参数之后,也就是方法中的最后一个参数
      
      def total2(from, to, &block)
          result = 0
          from.upto(to) do |num|
              if block
                  result += block.call(num)
              else
                  result += num
              end
          end
          return result
      end
  • 局部变量与块变量

    • 块内部的命名空间与外部是共享的
    x = 1
    y = 1
    ary = [1, 2, 3]
    
    ary.each do |x|
        y = x   #==> x值块的局部变量
                #==> 块内部,可以引用外部的局部变量y
    end

你可能感兴趣的:(Ruby)