GNU Smalltalk
GNU Smalltalk是Smalltalk編程語言的GNU計劃實現。
編程範型 | 面向對象, 腳本 |
---|---|
語言家族 | Smalltalk |
實作者 | Steve Byrne(直到1.1.5), Paolo Bonzini(自從1.6)[1] |
面市時間 | 2003年1月12日 |
當前版本 |
|
操作系統 | Unix(Linux, Cygwin, Mac OS X/Darwin) |
許可證 | GPL(針對虛擬機) + LGPL(針對類庫和映像) |
文件擴展名 | .st |
網站 | https://www.gnu.org/software/smalltalk/ |
影響語言 | |
Smalltalk-80, Ruby[3] |
這個實現不同於其他Smalltalk環境,使用文本文件作為程序輸入,並將其內容解釋為Smalltalk代碼[5]。在這種方式下,GNU Smalltalk表現得更像是一種解釋器,而非傳統Smalltalk方式下的一種環境[6]。GNU Smalltalk包括了對很多自由軟件庫的綁定,包括SQLite、libSDL、cairo、gettext和Expat等[7]。
簡單例子
下面的例子可工作在GNU Smalltalk 3.0和以後版本上。經典的Hello, World!例子:
'Hello, World!' displayNl
GNU Smalltalk聲明了三個文件:stdin
、stdout
和stderr
,作為文件串流類(FileStream
)的全局實例,並綁定了適合傳遞給C虛擬機的值。對象類(Object
)定義了特有於GNU Smalltalk的四個方法:print
、printNl
、store
和storeNl
。它們對接收者做一次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 <= 9
或A <= 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函數。例如計算從1
到10
的平方:
(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
(這個數組的第一個元素)作為元素,結果為11
。11
接着成為在下一趟時的sum
,這時向它加上3
得到14
。14
接着加上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
的一個類,這個類有兩個實例變量name
和age
,它們有各自的變異子與訪問子。定義了有兩個關鍵字參數的類方法,用來創建新的類實例。定義了單獨用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
)及其子類的signal
或signal:
方法。錯誤類(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:
方法,它通過原始操作停止執行及或啟動調試器,並展示這個錯誤消息:
self halt. "halt encountered"
self halt: 'This is a message'.
self error: 'This is a message'
參見
引用
- ^ AUTHORS. [2022-02-10]. (原始內容存檔於2022-03-18).
- ^ https://ftp.gnu.org/gnu/smalltalk/.
- ^ Regular expression matching. [2022-02-09]. (原始內容存檔於2022-02-18).
The GNU Smalltalk regular expression library is derived from GNU libc, with modifications made originally for Ruby to support Perl-like syntax.
- ^ index : smalltalk.git. [2022-02-10]. (原始內容存檔於2022-03-07).
- ^ Syntax of GNU Smalltalk. [2022-02-09]. (原始內容存檔於2022-02-18).
- ^ Computer Programming using GNU Smalltalk. [2022-02-09]. (原始內容存檔於2022-04-06).
- ^ Packages. [2022-02-09]. (原始內容存檔於2022-02-18).