GNU Smalltalk

維基百科,自由的百科全書
跳至導覽 跳至搜尋
GNU Smalltalk
File:GNU Smalltalk logo.svg
編程範型面向對象, 腳本
語言家族Smalltalk
實作者Steve Byrne(直到1.1.5),
Paolo Bonzini(自從1.6)[1]
釋出時間2003年1月12日,​23年前​(2003-01-12
當前版本
    Module:EditAtWikidata第29行Lua錯誤:attempt to index field 'wikibase' (a nil value)
    作業系統UnixLinux, Cygwin, Mac OS X/Darwin
    許可證GPL(針對虛擬機) + LGPL(針對類庫和映像)
    文件擴展名.st
    網站https://www.gnu.org/software/smalltalk/
    影響語言
    ANSI Smalltalk

    GNU SmalltalkSmalltalk程式語言GNU計劃實現。

    這個實現不同於其他Smalltalk環境,使用文本文件作為程序輸入,並將其內容解釋為Smalltalk代碼[3]。在這種方式下,GNU Smalltalk表現得更像是一種解釋器,而非傳統Smalltalk方式下的一種環境[4]。GNU Smalltalk包括了對很多自由軟件庫的綁定,包括SQLitelibSDLcairogettextExpat英語Expat (library)[5]

    簡單例子[編輯]

    下面的例子可工作在GNU Smalltalk 3.0和以後版本上。經典的Hello, World!例子:

    'Hello, World!' displayNl
    

    GNU Smalltalk聲明了三個文件:stdinstdoutstderr,作為文件串流類(FileStream)的全局實例,並綁定了適合傳遞給C虛擬機的值。對象類(Object)定義了特有於GNU Smalltalk的四個方法:printprintNlstorestoreNl。它們對接收者做一次printOn:storeOn:Transcript對象。這個對象是文本搜集器類(TextCollector)的唯一實例,它通常將寫操作委託給stdout

    一些基本的Smalltalk代碼:

    "所有东西,包括一个文字,都是一个对象,所以如下可行:"
    -199 abs.                                               "199"
    'gst is cool' size.                                     "11"
    'Slick' indexOf: $c.                                    "4"
    'Nice Day Isn''t It?' asLowercase asSet asSortedCollection asString "' ''?acdeinsty'"
    

    兩個"包圍的是註釋;$c是字符常量c;兩個'包圍的是字符串,字符串中的'''轉義序列

    搜集[編輯]

    構造和使用一個數組

    a := #(1 'hi' 3.14e0 1 2 (4 5)).
    
    a at: 3.       "3.14"
    a reverse.     "((4 5) 2 1 3.14 'hi' 1)"
    a asSet        "Set(1 'hi' 3.14 2 (4 5))"
    

    構造和使用一個散列表,它是散列搜集類(HashedCollection)的子類即字典類(Dictionary)的實例:

    hash := Dictionary from: { 'water' -> 'wet'. 'fire' -> 'hot' }.
    hash at: 'fire'     "'hot'".
    
    hash keysAndValuesDo:
           [ :k :v | ('%1 is %2' % { k. v }) displayNl ].
    "=> fire is hot
     => water is wet"
    
    "删除 'water' -> 'wet'"
    hash removeKey: 'water'
    

    GNU Smalltalk在字符串類(String),和作為它的超類的數組式搜集類(ArrayedCollection)之間,又介入了特有的字符數組類(CharacterArray),它的%方法,將其接收者中具有的特殊轉義序列,替換為由參數給出的搜集中的元素,其中%n被替代為這個搜集的第n個元素(1 <= n <= 9A <= n <= Z)。這裏給它的搜集,是在{}之間包圍的,當前Smalltalk變體一般都提供的動態數組,其中的元素可以在運行時間求值。

    塊和迭代器[編輯]

    參數傳遞到是為閉包的一個塊:

    "remember被绑定到一个块."
    remember := [ :name | ('Hello, %1!' % { name }) displayNl ].
    
    "时机成熟时 -- 调用这个闭包!"
    remember value: 'world'
    "=> Hello, world!"
    

    從一個方法返回由兩個閉包構成的一個數組:

    Integer extend [
        asClosure [
            | value |
            value := self.
            ^{ [ :x | value := x ]. [ value ] }
        ]
    ].
     
    blocks := 10 asClosure.
    setter := blocks first.
    getter := blocks second.
    getter value.       "10"
    setter value: 21.   "21"
    getter value        "21"
    

    這裏用extend為現存的類擴展新方法是GNU Smalltalk特有的語法。

    下面的考拉茲猜想例子,展示將兩個塊傳遞給接收者,並將結果信息發送回到調用者:

    Integer extend [
        ifEven: evenBlock ifOdd: oddBlock [
            ^self even
                ifTrue: [ evenBlock value: self ]
                ifFalse: [ oddBlock value: self ]
        ]
    ].
    
    10 ifEven: [ :n | n / 2 ] ifOdd: [ :n | n * 3 + 1 ]    "5"
    

    搜集類(Collection)的collect:方法,將接收者的每個元素傳遞給一個塊來求值,返回這些結果的搜集。這類似於函數式編程語言中map函數。例如計算從110的平方:

    (1 to: 10) collect: [ :x | x squared ] "(1 4 9 16 25 36 49 64 81 100 )"
    

    可迭代類(Iterable)定義了由子類實現的do:方法,將一個塊迭代於接收者的每個元素之上。這也被稱為隱式迭代器。例如迭代於數組和區間之上:

    array := #(1 'hi' 3.14e0).
    array do: [ :item | item displayNl ].
    "=> 1"
    "=> hi"
    "=> 3.14"
    
    (3 to: 6) do: [ :item | item displayNl ]
    "=> 3"
    "=> 4"
    "=> 5"
    "=> 6"
    

    可迭代類的inject:into:方法,接受一個參數和一個塊二者;它迭代於接收者的每個元素之上,在其上執行某個函數並保持結果為一個聚集。這類似於函數式編程語言中foldl函數。這個方法是憑藉調用do:方法實現的。例如:

    #(1 3 5) inject: 10 into: [ :sum :element | sum + element ] "19"
    

    在第一個趟時,這個塊接受10(要注入的實際參數)作為sum ,和1(這個數組的第一個元素)作為元素,結果為1111接着成為在下一趟時的sum,這時向它加上3得到1414接着加上5,最終返回19

    塊可以和很多內建方法一起工作,下面例子向一個文件寫一行文本,然後再讀取它的每一行並顯示:

    (File name: 'file.txt') withWriteStreamDo:
        [ :file | file nextPutAll: 'Wrote some text.'; nl ]
    
    (File name: 'file.txt') readStream linesDo:
        [ :each | each displayNl ] ; close
    "=> Wrote some text."
    

    文件類(File)的特有於GNU Smalltalk的name:方法,返回具有絕對路徑的文件名。GNU Smalltalk有特有的文件路徑類(FilePath),它的withWriteStreamDo:方法,對接收者調用writeStream方法打開一個只寫的文件串流類(FileStream)實例,在其上調用一個塊,並在這個塊的動態範圍結束處保證(ensure:)關閉這個串流;它的readStream方法,在接收者上打開一個只讀的文件串流類(FileStream)實例。

    串流類(Stream)的特有於GNU Smalltalk的linesDo:方法,對它的接收者的每一行都求值它的參數塊一次。 在GNU Smalltalk中,文件串流類(FileStream)的超類,不再是作為可定位串流類(PositionableStream)子類的讀寫串流類(ReadWriteStream),而是其特有的作為串流類(Stream)子類的文件描述符類(FileDescriptor),它的close方法關閉這個文件。

    [編輯]

    GNU Smalltalk建立新類採用特有的語法形式:

    超类名字 subclass: 新类名字 [
        | 诸实例变量 |
        pragmas
        消息模式1 [ 诸语句 ]
        消息模式2 [ 诸语句 ]
        ...
        类变量1 := 表达式.
        类变量2 := 表达式.
        ...
    ]
    

    類似的,為現存的類擴展新方法採用特有的語法形式:

    类表达式 extend [
        ...
    ]
    

    在Smalltalk有關書籍中有一個常見版式約定,將一個類中的方法引用為类名字 >> 方法名字,這不是Squeak/Pharo語法的一部份,GNU Smalltalk將类名字 class >> 方法名字作為定義類方法的語法形式。

    下面的代碼定義叫做Person的一個類,這個類有兩個實例變量nameage,它們有各自的變異子與訪問子。定義了有兩個關鍵字參數的類方法,用來創建新的類實例。定義了單獨用age來進行比較的<方法,通過從Magnitude派生,這個類自動繼承了所有的其他比較方法的定義。這個類還通過覆寫printOn:的方式,定製了這個對象的打印(print)/顯示(display)方式:

    Magnitude subclass: Person [
        | name age |
        Person class >> name: name age: age [
            ^self new name: name; age: age; yourself
        ]
    
        < aPerson [ ^self age < aPerson age ]
        name [ ^name ]
        name: value [ name := value ]
        age [ ^age ]
        age: value [ age := value ]
        printOn: aStream [ aStream nextPutAll: ('%1 (%2)' % { name. age }) ]
    ].
    
    group := {
        Person name: 'Dan' age: 23.
        Person name: 'Mark' age: 63.
        Person name: 'Cod' age: 16
    }.
    
    group asSortedCollection reverse
    

    這裏用asSortedCollection方法對搜集進行排序,然後用reverse方法來做反轉。最終結果是按age反序打印了三個人的信息:

    OrderedCollection (Mark (63) Dan (23) Cod (16) )
    

    異常[編輯]

    要發起能夠捕獲的異常,需要調用異常類(Exception)及其子類的signalsignal:方法。錯誤類(Error)表示不可恢復的致命錯誤,警告類(Warning)表示重要但可恢復的錯誤,停機類(Halt)表示通常是漏洞(bug)的可恢復錯誤。例如:

    Error signal.
    Error signal: 'Illegal arguments!'
    

    異常通過塊閉包(BlockClosure)的on:do:方法來處理,還可以只捕獲特定的異常(和它們的子類):

    [ 做些事情
    ] on: Exception do: [ :ex |
        处理ex中异常
    ]
    
    [ 做些事情
    ] on: Warning do: [ :ex |
        处理ex中异常
    ]
    

    處理器子句使用它能獲得的異常對象,可以退出或恢復一個塊;退出是缺省的,但也可以顯式的指示:

    [ Error signal: 'foo' 
    ] on: Error do: [ :ex |
        ex return: 5
    ]
    
    (Warning signal: 'now what?') printNl     "=> nil"
    
    [ (Warning signal: 'now what?') printNl
    ] on: Warning do: [ :ex |
        ex resume: 5 
    ]                "=> 5"
    

    在因異常狀況而要進入調試器,可以調用對象類(Object)的halt方法,或增加了一個消息參數的halt:方法;這二者實際上調用了對象類的error:方法,它通過原始操作停止執行及或英語And/or啟動調試器,並展示這個錯誤消息:

    self halt. "halt encountered"
    self halt: 'This is a message'.
    self error: 'This is a message'
    

    參見[編輯]

    引用[編輯]

    1. ^ AUTHORS. [2022-02-10]. (原始內容存檔於2022-03-18). 
    2. ^ index : smalltalk.git. [2022-02-10]. (原始內容存檔於2022-03-07). 
    3. ^ Syntax of GNU Smalltalk. [2022-02-09]. (原始內容存檔於2022-02-18). 
    4. ^ Computer Programming using GNU Smalltalk. [2022-02-09]. (原始內容存檔於2022-04-06). 
    5. ^ Packages. [2022-02-09]. (原始內容存檔於2022-02-18). 

    外部連結[編輯]