GNU Smalltalk
![]() | |
编程范型 | 面向对象, 脚本 |
---|---|
语言家族 | 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] |
GNU Smalltalk是Smalltalk编程语言的GNU计划实现。
这个实现不同于其他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).