莊周夢(mèng)蝶

          生活、程序、未來(lái)
             :: 首頁(yè) ::  ::  :: 聚合  :: 管理

          ruby查缺補(bǔ)漏

          Posted on 2007-04-07 10:30 dennis 閱讀(2337) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): 動(dòng)態(tài)語(yǔ)言
              《Programming Ruby中文版》前3部分我并不準(zhǔn)備細(xì)看,畢竟我接觸ruby也有一段時(shí)間了,只準(zhǔn)備快速地掠過(guò)一遍,查缺補(bǔ)漏;重點(diǎn)放在第3部分的核心內(nèi)容上,至于第四部分的參考手冊(cè)更多作為工具書(shū)了。僅在此記錄下一些值的注意的東西。

          1.全局變量$_,默認(rèn)當(dāng)gets方法返回輸入的行時(shí),同時(shí)保存在全局變量$_,并且正則表達(dá)式如果作為條件語(yǔ)句(if或者while)時(shí)默認(rèn)是跟這個(gè)全局變量進(jìn)行匹配,而print參數(shù)為空時(shí)也是打印這個(gè)全局變量。這是早期ruby向perl語(yǔ)言學(xué)習(xí)的結(jié)果。可以看看這個(gè)例子:
          while gets
            
          if /Ruby/
                print
            end
          end

          這樣的風(fēng)格不值的提倡,全局變量的使用應(yīng)該盡力減少,ruby也在逐漸脫離perl主義的風(fēng)格

          2.ruby中的單例模式:
          class Logger
            private_class_method:new
            @@logger
          =nil
            
          def Logger.create
              @@logger
          =new unless @@logger
              @@logger
            end
          end
          log1
          =Logger.create
          log2
          =Logger.create

          puts log1.object_id
          puts log2.object_id

          3.ruby中的block作用:
          1)迭代器,通常是內(nèi)部迭代器
          2)事務(wù)Blocks,c#的using語(yǔ)句倒是跟這個(gè)有點(diǎn)像,其實(shí)就是讓對(duì)象自身負(fù)責(zé)資源的打開(kāi)和關(guān)閉,這是通過(guò)Kernel.block_given?實(shí)現(xiàn)的,比如File.open方法,當(dāng)后面跟著一個(gè)block的時(shí)候,就會(huì)自動(dòng)關(guān)閉打開(kāi)的文件資源,如果不是,就需要自己處理。
          3)作為閉包,與javascript和其他語(yǔ)言中的閉包概念一致,一個(gè)例子:
          def n_times(thing)
            
          return lambda {|n| thing*n}
          end
          p1
          =n_times(23)
          puts p1.call(
          3)
          puts p1.call(
          2)
          通過(guò)lambda方法將一個(gè)block轉(zhuǎn)為Proc對(duì)象,盡管參數(shù)thing在block被真正調(diào)用時(shí)已經(jīng)離開(kāi)了作用范圍,但是仍然可以使用

          4.ruby中數(shù)字的最大長(zhǎng)度取決于系統(tǒng),這跟java,C#通過(guò)虛擬機(jī)規(guī)范的不同,數(shù)字類(lèi)型的幾個(gè)常用迭代器:times,upto,downto,step,如:
          2.step(10,2){|i| print i,' '}  =>2,4,6,8,10

          5.ruby中的字符串是8字節(jié)的序列,可以存儲(chǔ)可打印的字符和二進(jìn)制數(shù)據(jù)。比較有趣3種構(gòu)建字符串常量方式:%q(對(duì)應(yīng)于單引號(hào)定義的字符串),%Q(雙引號(hào))以及here documents,比如:
          s=<<END_OF_STRING
             測(cè)試測(cè)試?yán)?br>END_OF_STRING

          6.Range,書(shū)中翻譯為區(qū)間,我倒更喜歡范圍這個(gè)詞。區(qū)間的3個(gè)用途:
          1)用作序列,最常見(jiàn)的,如1..2,a..z等,可以定義自己的區(qū)間,只要實(shí)現(xiàn)succ和<=>比較方法
          2)作為條件,書(shū)中的例子很經(jīng)典:
          while line=gets
             puts line 
          if line=~/start/..line=~/end/
          end

          #利用全局變量簡(jiǎn)化為,不建議這樣寫(xiě)
          while gets
             
          print if /start/../end/
          end

          3)作為間隔,看看某個(gè)值是否落入?yún)^(qū)間范圍內(nèi),使用===操作符比較

          7.正則表達(dá)式,這是重頭戲。ruby中的perl風(fēng)格的正則表達(dá)式,其實(shí)也是內(nèi)建在ruby中的正則表達(dá)式對(duì)象的外部包裝,關(guān)鍵的就是兩個(gè)類(lèi)Regexp類(lèi)和MatchData類(lèi)。一些peri程序員熟悉的記號(hào):
          $&    匹配的字符串
          $`    匹配前的字符串
          $'    匹配后的字符串
          $1    第一個(gè)分組,$2,$3...類(lèi)似
          詳細(xì)的就不抄書(shū)了,正則表達(dá)式我在學(xué)習(xí)javascript的時(shí)候已經(jīng)系統(tǒng)地學(xué)過(guò),倒是不感覺(jué)吃力。

          8.在方法中定義可變長(zhǎng)度參數(shù),只要參數(shù)前加*號(hào)即可,java1.5也已經(jīng)支持可變參數(shù),比如Object...obj。
          另外,在方法中,將數(shù)組展開(kāi)為參數(shù),可以在數(shù)組前加一個(gè)*號(hào),比如:
          def three(a,b,c)
             
          print "this is #{a},#{b},#{c}"
          end

          three([
          1,2,3)]
          #上面這樣調(diào)用報(bào)參數(shù)數(shù)目錯(cuò)誤,正確的用法如下:
          three(*[1,2,3)] =>this is 1,2,3
          將hash列表直接做為參數(shù),可能在2.0支持,目前采用的要求散列數(shù)組在正常的參數(shù)之后,并位于任何的block或者數(shù)組之前

          9.ruby中的多線程:
          1)ruby創(chuàng)建線程,見(jiàn)下面這個(gè)例子,開(kāi)3個(gè)線程分別訪問(wèn)3個(gè)站點(diǎn),并且對(duì)3個(gè)線程通過(guò)調(diào)用join方法,直到3個(gè)線程都結(jié)束,主線程才結(jié)束,來(lái)自書(shū)中例子:
          require 'net/http'
          pages
          =%w(www.javaeye.com www.sina.com.cn www.aygfsteel.com)
          $proxy_addr 
          = 'x.x.x.x'
          $proxy_port 
          = 80
          threads
          =[]
          for page_to_fetch in pages
            threads
          <<Thread.new(page_to_fetch) do |url|
              h
          =Net::HTTP.Proxy($proxy_addr, $proxy_port).new(url,80)
              puts 
          "Fetcing:#{url}"
              resp
          =h.get('/',nil)
              puts 
          "Got #{url}:#{resp.message}"
            end
          end    
          threads.each{
          |thr| thr.join}

          2)線程中如何共享變量?可以通過(guò)[]=簡(jiǎn)單地把當(dāng)前線程看成一個(gè)散列表,這里沒(méi)有考慮同步問(wèn)題:
          count=0
          threads
          =[]
          10.times do |i|
            threads[i]
          =Thread.new do 
              sleep(rand(
          0.1))
              Thread.current[
          "mycount"]=count
              count
          +=1
            end
          end
          threads.each{
          |t| t.join;print t["mycount"],""}
          puts 
          "count =#{count}"

          3)通過(guò)設(shè)置abort_on_exception,如果是true,未處理的線程異常將殺死所有正在運(yùn)行的線程,如果是false,則殺死當(dāng)前運(yùn)行的線程,其他線程繼續(xù)運(yùn)行。修改上面的例子查看下:
          count=0
          threads
          =[]
          10.times do |i|
            threads[i]
          =Thread.new(i) do |j|
              
          raise "boom!" if j==4 
              sleep(rand(
          0.1))
              Thread.current[
          "mycount"]=count
              count
          +=1
            end
          end
          threads.each do 
          |t|
            begin
              t.join
              
          print t["mycount"],""
            rescue RuntimeError
          =>e
              puts 
          "Failed:#{e.message}"
            end
          end
          puts 
          "count =#{count}"
          輸出(隨機(jī)的):
          8, 1, 6, 3, Failed:boom!
          2, 4, 7, 0, 5, count =9

          在開(kāi)頭加上:
          Thread.abort_on_exception=true
          殺死所有的運(yùn)行進(jìn)程,報(bào)出異常,而不會(huì)產(chǎn)生輸出。

          4)通過(guò)線程的一系列方法:pass,join,value,stop來(lái)進(jìn)行線程的調(diào)度
          5)互斥的實(shí)現(xiàn),與其他語(yǔ)言一樣,不外乎加鎖、信號(hào)量、隊(duì)列的方式。看看加鎖是如何做的,通過(guò)monitor庫(kù)的關(guān)鍵字synchronize實(shí)現(xiàn),如下面這個(gè)例子,兩個(gè)線程遞增同一個(gè)變量,似乎結(jié)果應(yīng)該是20000:
          #require 'monitor'
          class Counter#<Monitor
            attr_reader:count
            
          def initialize
              @count
          =0
            
          #  super
            end
            
          def tick
            
          #  synchronize do
                @count+=1
            
          #  end
            end
          end
          c
          =Counter.new
          t1
          =Thread.new{10000.times{c.tick}}
          t2
          =Thread.new{10000.times{c.tick}}

          t1.join;t2.join

          print c.count
          很遺憾,結(jié)果不會(huì)是20000,而是比它小的一個(gè)數(shù)值,這里的問(wèn)題就是因?yàn)樵L問(wèn)共享資源沒(méi)有進(jìn)行同步的緣故,使用monitor庫(kù),請(qǐng)將上面代碼中的注釋去掉,可以得到正確的結(jié)果
          使用monitor,不一定要使用繼承,也可以使用mixin,甚至:
          lock=Monitor.new
          t1
          =Thread.new{10000.times{lock.synchronize{c.tick}}}
          還可以把特定的對(duì)象放入monitor,比如:
          c=Counter.new
          c.extend(MonitorMixin)
          t1
          =Thread.new{10000.times{c.synchronize{c.tick}}}
          .

          6)條件變量和隊(duì)列的方式不準(zhǔn)備抄書(shū)了,ruby中對(duì)線程的操作都是直接調(diào)用操作系統(tǒng)的命令,特別是*nix支持的非常好,可惜我對(duì)linux也是個(gè)初哥。

          10.ruby中表達(dá)式很重要的一個(gè)特點(diǎn)是:任何表達(dá)式都有返回值,包括賦值語(yǔ)句、條件語(yǔ)句、循環(huán)語(yǔ)句之類(lèi)。
          1)ruby中對(duì)布爾表達(dá)式的規(guī)定是:任何不是nil或者常量false的值都為真
          2)注意,在方法中調(diào)用訪問(wèn)屬性的函數(shù),需要寫(xiě)上調(diào)用者self,否則將處理為局部變量
          3)defined?方法用于返回參數(shù)的描述,如果未定義,返回nil
          4)邏輯表達(dá)式中,and和or的優(yōu)先級(jí)低于&&,||
          5)ruby沒(méi)有for語(yǔ)句,因?yàn)閞uby通過(guò)內(nèi)建在對(duì)象中的迭代器提供了循環(huán)訪問(wèn)的能力,最簡(jiǎn)單的內(nèi)建迭代器:loop do ....end
          6)只要你的類(lèi)支持each方法,你就可以使用for ... in ..語(yǔ)句循環(huán)它
          7)對(duì)循環(huán)可以使用break(打斷跳出),redo(從頭重新循環(huán),當(dāng)前迭代),next進(jìn)行調(diào)度。另外,還有retry,用于完全重新開(kāi)始循環(huán)
          8)while,until和for循環(huán)內(nèi)建到了ruby語(yǔ)言中,但沒(méi)有引入新的作用域:前面存在的局部變量可以在循環(huán)中使用,而循環(huán)中新創(chuàng)建的局部變量也可以在循環(huán)后使用。而被迭代器使用的block則不同,在block中創(chuàng)建的局部變量無(wú)法在block外訪問(wèn)。

          11.ruby的異常處理
          類(lèi)似于java的try...catch...finnaly,ruby對(duì)應(yīng)的是begin...rescue...ensure...end,將產(chǎn)生異常的代碼放在這個(gè)塊中進(jìn)行處理。可以通過(guò)$!得到異常信息,或者提供局部變量名,我改寫(xiě)了一下我的google在線翻譯機(jī),增加異常處理,并用exit代替break:
          require 'net/http'
          def translate
            txt
          =STDIN.gets
            exit 
          if txt.strip=='e' or txt.strip=='exit'
            temp
          =txt.split(' ')
            
          if temp[1]=='1' or temp.size==1
              langpair
          ='en|zh-CN'
            
          else
              langpair
          ='zh-CN|en'
            end
            
          #使用代理  
            begin 
              $proxy_addr 
          = 'localhost'
              $proxy_port 
          = 80
              response 
          = Net::HTTP.Proxy($proxy_addr,$proxy_port).post_form(URI.parse("http://translate.google.com/translate_t"),{'text'=>temp[0],'langpair'=>langpair})
              response.body 
          =~ /<div id=result_box dir=ltr>(.*)<\/div>/
            rescue  StandardError 
          =>e
              $stderr.
          print "網(wǎng)絡(luò)錯(cuò)誤:"+e
            
          else
              result 
          = $1 
              puts 
          '翻譯內(nèi)容:'+temp[0]
              puts 
          'google返回:'+result
              puts 
          '-------------------退出請(qǐng)打e或者exit---------------'
              translate
            end
          end
          translate
          引發(fā)一個(gè)異常使用raise語(yǔ)句,重新引發(fā)當(dāng)前異常,如果沒(méi)有,就引發(fā)一個(gè)RuntimeError,常見(jiàn)使用方式:
          raise InterfaceException,"keyboard failure",caller
          其中的caller生成了棧的信息。另外,catch...throw語(yǔ)句用于在異常發(fā)生時(shí)從深度嵌套的結(jié)構(gòu)中跳轉(zhuǎn)出來(lái)。

          12。關(guān)于模塊,作用有二:作為命名空間和Mixin機(jī)制。模塊的Mixin機(jī)制可以說(shuō)是ruby的一個(gè)精華所在,通過(guò)Mixin,可以變相地實(shí)現(xiàn)了多重繼承,并且可以動(dòng)態(tài)地為類(lèi)添加和刪除功能。這一部分注意兩點(diǎn):
          1)模塊中定義的實(shí)例變量可能與包含模塊的類(lèi)的實(shí)例變量產(chǎn)生名稱(chēng)沖突。可以使用模塊一級(jí)的散列表,以當(dāng)前對(duì)象的ID做索引,來(lái)保存特定于當(dāng)前模塊的實(shí)例變量解決這個(gè)問(wèn)題。比如:
          module Test
            State
          ={}
            
          def state=(value)
              State[object_id]
          =value
            end
            
          def state
              State[object_id]
            end
          end
          class Client
            include Test
          end
          c1
          =Client.new
          c2
          =Client.new
          c1.state
          ='A'
          c2.state
          ='B'

          puts c1.state
          puts c2.state
          2)是關(guān)于方法的查找路徑,順序是:當(dāng)前類(lèi)-》類(lèi)的mixin模塊-》超類(lèi)-》超類(lèi)的mixin,另外mixin的模塊,最后混入的同名方法將覆蓋前面混入的。

          13.irb的配置和命令,今天發(fā)現(xiàn)irb原來(lái)也是可以玩出很多花樣的。記錄些有趣的:
          1)可以使用按tab鍵兩次來(lái)自動(dòng)補(bǔ)全,要求加載irb/completaion庫(kù)。比如這樣啟動(dòng)irb:
           
          irb -r irb/completion

          或者進(jìn)入irb后手工require:
          require 'irb/completation'

          當(dāng)然,還有更好的方法,呆會(huì)介紹
          2)子會(huì)話,在irb中使用irb可以創(chuàng)建子會(huì)話,通過(guò)命令jobs可以查看所有的子會(huì)話。創(chuàng)建子會(huì)話的時(shí)候指定一個(gè)對(duì)象,子會(huì)話的self將綁定該對(duì)象,比如:
          irb 'test'
          reverse
          =>"tset"
          length
          =>4
          self
          =>"test"
          irb_quit

          3)在linux下可以通過(guò)配置.irbrc配置文件來(lái)進(jìn)行初始化定制,在windows環(huán)境你可以在ruby安裝目錄下的bin看到一個(gè)irb.bat文件,通過(guò)配置文件來(lái)定制irb,比如我們?yōu)閕rb增加ri和tab自動(dòng)補(bǔ)齊功能:
          @echo off
          goto endofruby
          #!/bin/ruby
          #
          #
             irb.rb - intaractive ruby
          #
                 $Release Version: 0.9.5 $
          #
                 $Revision: 1.2.2.1 $
          #
                 $Date: 2005/04/19 19:24:56 $
          #
                 by Keiju ISHITSUKA(keiju@ruby-lang.org)
          #

          require 
          "irb"
          require 
          'irb/completion'
          def ri(*names)
            system(
          %{ri.bat #{names.map{ |name| name.to_s}.join(" ")}})
          end
          if __FILE__ == $0
            IRB.start(
          __FILE__)
          else
            
          # check -e option
            if /^-e$/ =~ $0
              IRB.start(
          __FILE__)
            
          else
              IRB.setup(
          __FILE__)
            end
          end
          __END__
          :endofruby
          "%~d0%~p0ruby" -"%~f0" %*

          4)常用命令:
          exit,quit,irb_exit,irb_quit——退出
          conf,context,irb_context——查看配置信息
          irb <obj>——?jiǎng)?chuàng)建子會(huì)話,如果提供obj,作為self
          jobs,irb_jobs——列出irb的子會(huì)話
          irb_fg,fg n——切換子會(huì)話
          kill n,irb_kill n——?dú)⑺酪粋€(gè)irb子會(huì)話

          14.類(lèi)的實(shí)例變量,類(lèi)除了類(lèi)變量、實(shí)例變量外,還有一個(gè)類(lèi)的實(shí)例變量的概念:
          class Test
            #類(lèi)的實(shí)例變量
            @cls_var 
          = 123
            def Test.inc
              @cls_var 
          += 1
            end
            
          class<<self
              attr_accessor:cls_var
            end
          end
          Test.inc
          Test.inc


          15.子類(lèi)竟然可以改變父類(lèi)定義方法的訪問(wèn)級(jí)別:
          class Base
            
          def aMethod
              puts 
          "Got here"
            end
            private :aMethod
          end

          class Derived1 < Base
            public :aMethod
          end

          class Derived2 < Base
            
          def aMethod(*args)
              super
            end
            public:aMethod  
          end

          d1
          =Derived1.new
          d2
          =Derived2.new
          d1.aMethod
          d2.aMethod

          不知道ruby是基于什么樣的考慮允許這樣的行為。













          主站蜘蛛池模板: 房产| 新龙县| 临高县| 刚察县| 临夏市| 祥云县| 保定市| 达州市| 普定县| 新民市| 丰顺县| 大悟县| 广元市| 博罗县| 阆中市| 米易县| 郓城县| 南靖县| 寻乌县| 讷河市| 大同县| 萨迦县| 宝鸡市| 十堰市| 涡阳县| 黑龙江省| 广河县| 肥城市| 关岭| 湖南省| 道真| 磐安县| 石首市| 江油市| 宝山区| 嘉善县| 大悟县| 美姑县| 张家川| 阿克| 沙雅县|