第三章 語法基礎(chǔ)

正如大多數(shù)現(xiàn)代Smalltalk方言,Squeak使用一種非常接近Smalltalk-80的語法。這個語法設(shè)計的非常符合英語閱讀習(xí)慣

(Smalltalk includes:Class) ifTrue:[Transcript show: Class superclass]

Squeak語法核心非常簡潔,僅僅包含方法聲明與消息發(fā)送語法。表達式基于少量的原語元素構(gòu)建。僅僅保護6個關(guān)鍵詞,沒有任何控制結(jié)構(gòu)語法和聲明新類語法。取而代之的是,邏輯控制ifelse等語言結(jié)構(gòu)使用發(fā)送消息ifTrue到布爾對象,創(chuàng)建新的子類發(fā)送superclass消息給父類。

3.1 語法要素

表達式保護以下的內(nèi)建塊結(jié)構(gòu):

  1. 六個保留關(guān)鍵詞 pseudo-variables:self super nil true false thisContext
  2. 字面量常量表達式 數(shù)字 字符 字符串 符號表和數(shù)組
  3. 變量聲明
  4. 變量賦值
  5. 塊結(jié)構(gòu)
  6. 消息發(fā)送

我可以看看表3.1中的語法要素使用例子

syntax

本地變量 Local 小寫

startPoint是一個變量名稱或標(biāo)識符。通常,標(biāo)識符使用駝峰大小寫camelCase。實例變量的首字符是小寫的,表明這個變量是私有作用域

共享變量 Shared 大寫

Transcript是一個全局變量,類TranscriptStream的實例。通常以大寫字母開頭。

消息接受者 Receiver

self是一個關(guān)鍵詞代表當(dāng)前方法所在的對象。我們將這個稱為消息接受者,因為通常用來接收消息來執(zhí)行方法。self稱為預(yù)定義變量不可以手動賦值

數(shù)字類型 Integers

squeak除了十進制42,還提供了其他類型的數(shù)字,2r101等

浮點數(shù)
squeak提供了十進制的浮點數(shù) 2.4e7

字符
字符使用$進行聲明 $a表示a。可以發(fā)生消息給字符Character類 來處理 如 space tab等

字符串
單引號用來定義字符串字面量,可以在單引號中使用雙號'G"day'

符號
與字符串類似,符號包含一系列的字符,然而不同于字符串,符號字面量是全局唯一的。#hello是一個符號對象 'Hello'是一個字符串

編譯時數(shù)組

使用#()定義編譯時數(shù)組,包含空格分隔的字面量。其中的參數(shù)必須是編譯時常量 #(27 #(true false) abc)是一個三個元素的編譯時字面量數(shù)組

運行時數(shù)組

使用{}定義運行時數(shù)組,其中的元素使用句號分隔 {1. 2. 1+2} 頂一個包含三個元素的運行時數(shù)組,

注釋

使用雙引號包圍字符串作為注釋"hello"。在smalltalk中雙引號不是字符串只是注釋說明

本地定義變量

使用||包含方法中的一個或多個本地變量定義

賦值

使用:=賦值對象變量。有時可以使用<-代替。因此x := 1 等價于x <- 1x _ 1。

塊語法

使用[]表明塊語法。作為塊語法或謂詞語法。通常代表一個一個方法對象。塊語法可以接受形參和本地變量

原語
使用<primitive:...>引入一個虛擬機原語,其中的原語代碼將會在原語執(zhí)行失敗時運行。

一元消息
僅僅一個方法名稱的消息
二元消息
包含一個參數(shù)的方法的消息
關(guān)鍵字消息
包含多個參數(shù)的方法的小

方法返回
可以使用^ 返回方法的運算結(jié)果
語句結(jié)束
可以使用.語法作為語法分隔符。
級聯(lián)消息
可以發(fā)送多個消息到一個對象,使用(;)實現(xiàn)級聯(lián)消息發(fā)送

3.2 預(yù)定義變量

在Smalltalk中,包含6個保留關(guān)鍵詞或者說是預(yù)定義變量
nil,true,false,self,super,thisContext。

這些預(yù)定義變量的值是運行環(huán)境決定的,無法進行手動賦值,
其中true,false,nil是常量值。
self,super,thisContext是動態(tài)變量值

truefalse是Boolean類的子類True和False的唯一實例對象。 在第八章詳細(xì)講解

nil代表未定義對象。是UndefinedObject類的唯一實例對象。實例變量通常初始化為nil

self 通常表示當(dāng)前方法所在的對象,也就是方法消息的接受者對象。

super當(dāng)前方法所在對象的父級,發(fā)送消息給super,方法查找將會從當(dāng)前對象類的父類開始進行查找。這個在第5章詳解

thisContext代表運行棧的頂幀。也就是說,代表當(dāng)前運行方法上下文,塊上下文。在大多數(shù)開發(fā)過程中不需要關(guān)心當(dāng)前上下文,但是在實現(xiàn)調(diào)試器等開發(fā)工具中非常有用,也會用來實現(xiàn)異常處理和繼續(xù)運行。

3.3 消息發(fā)送

在Squeak中包含三類消息

  1. 一元消息 (Unary message)
    通常不需要參數(shù),如1 factorial發(fā)送消息factorial給數(shù)字對象 1

2 .二元消息(Binary message)
通常需要一個參數(shù),如1 + 2發(fā)送消息+攜帶一個參數(shù)2給數(shù)字對象 1

  1. 關(guān)鍵字消息(Keyword message)
    通??梢詳y帶任意數(shù)量的參數(shù), 如2 raisedTo: 6 modulo: 10 發(fā)送消息包含多個消息選擇器raisedTo: modulo:分別包含參數(shù)6 10到數(shù)字對象 2

一元消息選擇器通常使用字符數(shù)字字符,通常使用小寫字母開頭

二元消息選擇器包含以下的一個或多個字符
+-/\*~<>=@%|&?,

關(guān)鍵詞消息選擇包含一系列的關(guān)鍵詞,每個關(guān)鍵詞都使用小寫字母開頭并以分號結(jié)束

一元消息選擇器通常有最高的優(yōu)先級,然后是二元消息選擇器,最后是關(guān)鍵詞消息選擇器
2 raisedTo: 1 + 3 factorial

我們首先發(fā)送 factorial到數(shù)字對象3,然后發(fā)送6到數(shù)字對象1,最后我們發(fā)送raisedTo: 7到數(shù)字對象2.
我們可以使用表達式—>表示這個表達式的計算結(jié)果

如果不考慮優(yōu)先級,我們通常直接計算如下
1 + 2 * 3 —> 9
因為沒有優(yōu)先級,所以先計算得到3然后相乘得到9
然而我們包含的優(yōu)先級法則如下
1 + (2 * 3) —> 7

消息發(fā)送可以使用句號和分號進行組合。

一個句號分隔符可以將一系列表達式的依次一個接一個的運行。

Transcript cr.
Transcript show: 'hello world'.
Transcript cr

上面的語句將會發(fā)送cr,show:'hello world'到Transcript。最后再次發(fā)送cr。

當(dāng)多個消息被發(fā)送到相同的接受者,這些消息將會按照級聯(lián)消息運行。接受者只需要被指明一次,一系列的消息按照級聯(lián)的方式發(fā)送給消息接受者

Transcript cr;
  show: 'hello world';
  cr

上面兩個表達式的執(zhí)行結(jié)果將會相同

3.4 消息語法

在Squeak中,一個表達式可以在workspace,debugger,browser等任意的地方運行。

方法的定義可以在系統(tǒng)查看器或者調(diào)試器中

編程者通常在給的類的上下文中開發(fā)一個方法,一個類的定義通過發(fā)送消息給已存在的類,要求創(chuàng)建一個子類,因此不需要使用特定的語法來定義新的類

下面是字符串類String中定義lineCount的方法。

lineCount

通常一個方法的定義包含以下結(jié)構(gòu)

  1. 方法參數(shù),包含方法名稱和任意多個參數(shù)(lineCount)
  2. 方法注釋,方法體中雙引號中的字符串形描述
  3. 本地變量,使用||聲明的本地變量
    4.方法體表達式,使用句號分隔的方法體表達式。

可以使用^終止方法運行,返回運行結(jié)果。
一個方法沒有包含顯式返回值的將默認(rèn)返回self,
這個默認(rèn)實現(xiàn)鏈?zhǔn)竭\算

參數(shù)和本地變量通常以小寫字母開頭,大寫字母開頭的變量假設(shè)為全局變量。例如Character類,僅僅是簡單的全局變量代表字符類對象。

3.5 塊語法

塊語法提供一種機制來定義表達式的運算。一個塊語法通常是匿名函數(shù)??梢越o塊語法發(fā)送value求值一個塊語法。塊語法可以使用^顯示表明返回值,默認(rèn)的通常返回一系列表達式最后一個表達式的值,

[1 + 2] value —> 3

塊語法作為匿名函數(shù),還可以接受形參,通常使用分號開頭作為形參聲明。使用垂直線分割形參與塊語法

[:x | 1 + x] value: 2 —> 3
[:x :y | x + y] value: 1 value: 2 —> 3

如果塊語法包含多余四個參數(shù)的,必須使用valueWithArguments:,并且以數(shù)組形式傳遞參數(shù)。
包含多個參數(shù)的塊語法通常拾遺設(shè)計錯誤的標(biāo)志

塊語法中可以聲明本地變量,使用雙豎線聲明本地變量,通常本地變量在參數(shù)之后聲明

[:x :y | |z| z := x+y. z] value: 1 value: 2 —> 3

塊語法事實上詞法作用域,因為我們可以將當(dāng)前塊的包圍環(huán)境作為變量的作用域。下面的塊語法限制了x變量作用范圍

|x|
x := 1
[:y | x + y] value:2 —> 3

塊語法通常是類BlockContext類的實例對象。也就是說它們僅僅是對象,可以被賦值給變量或者作為參數(shù)傳遞給任何其他對象

3.6 條件與循環(huán)控制

smalltal并沒有提供任何特殊的語法用來實現(xiàn)控制結(jié)構(gòu)。相反,這些僅僅典型的通過發(fā)送以語法塊作為參數(shù)發(fā)送消息給布爾值,數(shù)字或者集合,

條件語句通常發(fā)送ifTure:,ifFalse: ifTrue:ifFalse:給布爾值變量。

(17*13>220)
  ifTrue:['bigger']
  ifFalse:['smaller']  —>'bigger'

循環(huán)語句通常典型的發(fā)送消息給塊,數(shù)字或者集合。因為循環(huán)語句的跳出條件或許會被反復(fù)運行,因此條件語句組織為一個可執(zhí)行的塊語法而不是一個布爾變量值,下面是一個典型的循環(huán)

n := 1.
[n < 1000] whileTrue: [ n := n*2].
n —> 1024

whileFlase: 用來退出循環(huán)

n := 1.
[n > 1000] whileFalse: [n := n*2].
n —> 1024

timeRepest: 實現(xiàn)固定次數(shù)循環(huán)

n := 1.
10 timesRepeat: [n := n*2].
n —> 1024

還可以使用to:do發(fā)送給一個數(shù)字,這個數(shù)字作為循環(huán)計數(shù)的初始化值。第二個參數(shù)作為上限,語法塊接受當(dāng)前計數(shù)值,運行求值結(jié)果

n := 0 .
1 to: 10 do: [:counter | n:= n + counter ] .
n —> 55

高級迭代器。集合中包含大量的不同的類,這些類通常支持相同的協(xié)議??梢杂糜诩系南㈩愑?code>do:,collect:,select:,reject:,detect: inject:into:。這些消息定義了較為高級的迭代器。使用這些迭代器可以簡化代碼

Interval可以作為一系列數(shù)字集合,通常包含開始與結(jié)束位置信息。1 to: 10代表從1到10的數(shù)字集合。因為這個是數(shù)字集合,我們可以發(fā)送do:給數(shù)字集合,攜帶一個塊語法參數(shù)可以用來遍歷執(zhí)行

n := 0.
(1 to: 10) do: [:element|n := n +element ].
n —>  55

可以使用 collect:構(gòu)建一個集合,轉(zhuǎn)換元素集合

(1 to: 10) collect:[:each|each * each]
—> #(1 4 9 16 25 36 49 64 81 100)

可以使用select:reject:構(gòu)建新的集合,每個包含(不)符合一定條件的選擇內(nèi)容。detect:返回固定集合的第一個元素

'hello there' select: [:char | char isVowel] —>  'eeee'
'hello there' reject:  [:char | char isVowel] —> 'hll thr'
'hello there' detect: [:char | char isVowel] —> $e

最終,有些集合在inject:into:方法中支持fold運算符。
通常我們使用一個種子值然后使用一個表達式累積起來得到結(jié)果,通常使用求和和求積

(1 to: 10) inject: 0 into:[:sum :each |sum + each]
—> 55

等價于使用
0+1+2+3+4+5+6+7+8+9+10

更多的有關(guān)集合與流的操作可以在第九章與第十章中找到

3.7 原語與程序組織

在smalltalk中,每個變量都是對象,每個變量都可以發(fā)送消息。然而,特定的時刻我們可能接觸到巖底。特定的對象僅僅通過調(diào)用虛擬機的原語才可以得到執(zhí)行

比如,下面的操作通常實現(xiàn)為原語結(jié)構(gòu):內(nèi)存操作(new new:),二進制運算(bitAnd:,bitOr:,bitShift),指針操作和數(shù)字運算(+ - < > * / = ==)還有數(shù)組訪問(at:,at:put:)

原子操作可以調(diào)用原子語法實現(xiàn)<primirive:aNumber>。調(diào)用原語操作的過程可能包含Smalltalk代碼,通常是在原語執(zhí)行失敗的時候運行。

可以查看SmallInteger>>+代碼。如果原語執(zhí)行失敗,表達式 + aNumber將會得到執(zhí)行并返回

+ aNumber
  <privmitive: 1>
^ super + aNumber

Squeak3.9后,尖括號語法也會用在方法作為編譯指示的注釋使用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,563評論 19 139
  • 國家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 12,416評論 6 13
  • 第5章 引用類型(返回首頁) 本章內(nèi)容 使用對象 創(chuàng)建并操作數(shù)組 理解基本的JavaScript類型 使用基本類型...
    大學(xué)一百閱讀 3,679評論 0 4
  • 對于很多年輕人來說,第一套房子總是來之不易的,特別是對于剛結(jié)婚的小夫妻來說,錢總是不夠用!預(yù)算有限的情況下,還要住...
    武漢豐立裝飾姜玲閱讀 252評論 0 1
  • 開頭起了好幾個,但是刪刪寫寫到最后就成了這樣。就好象新的一個月的開始,你覺得這又是一個新的開始,從昨晚就像,這新的...
    橘子是怪獸閱讀 232評論 0 1

友情鏈接更多精彩內(nèi)容