匿名類指類定義體(即代碼塊)本身,使得類也成為所謂的“一等公民”,類也可以像變數一樣進行賦值定義、傳遞和使用。S#語言的數據類就是程式代碼,數據表是該代碼運行時對應的數據值,為此本文介紹了數據表、類定義和類實例化的各種使用方法,讓你體驗S#強大的數據和信息表達能力。 ...
ShoneSharp語言(S#)的設計和使用介紹
系列(11)—“類”披炫服靚妝化成“表”
作者:Shone
聲明:原創文章歡迎轉載,但請註明出處,https://www.cnblogs.com/ShoneSharp。
摘要: 匿名類指類定義體(即代碼塊)本身,使得類也成為所謂的“一等公民”,類也可以像變數一樣進行賦值定義、傳遞和使用。S#語言的數據類就是程式代碼,數據表是該代碼運行時對應的數據值,為此本文介紹了數據表、類定義和類實例化的各種使用方法,讓你體驗S#強大的數據和信息表達能力。
軟體: S#語言編輯解析運行器13.6.31,運行環境.NET 4.0,綠色軟體,單個EXE直接運行,無副作用。網盤下載鏈接為https://pan.baidu.com/s/1nv1hmJn
有了前述S#公式、函數以及語句的鋪墊,終於進入到本系列的高潮部分介紹———S#類,為配合本文例子,請使用最新軟體13.6.31版運行本文示例。
一、引言
世界很複雜,世界也很簡單。站在不同角度,收穫視圖也不一樣。前面第四章第二節已經清晰地展示S#符號解析運行視圖,提到了:
S#語言開始處理的是數據,最終獲得的也是數據,從而形成周而複始的閉環,最終用於實現“數據 → 信息 → 智慧”的完美進化。
S#語言的表達其實也是數據加工成信息的過程,即從沒有意義的數據,變成有指定意義的數據(信息)。那麼怎麼表達呢?
S#第一定律:萬物皆對象,對象皆引用。
S#把所有數據值都看成是一個.NET Object對象,可以表達任意數據類型的數據值,而且所有數據都是.NET引用,預設情況下後面的操作不應修改引用數據的內容,而會產生新的應用,保證數據表達或加工過程不產生副作用。
S#第二定律:程式就是樹,代碼即節點。
S#把程式代碼本身也看成是一棵語法數據樹,每個樹節點對應不同的語法結構代碼,可以包含運行過程生成的數據值。因此可以把樹節點看成是其數據值的包裝,而且樹節點本身也是一種數據值,這樣就會統一了程式與數據之間的關係,達到“程式即數據,數據即程式”的無縫融合。
S#第三定律:程式以類聚,數據以表分。
第二定律指出程式也是數據,而程式與數據的關係是動態映射的。在程式運行過程中程式的一個數據節點通常保持不變,但其包含的數據值卻是根據上下文動態變化的,即不同實例的數據值。因此相同功能的程式代碼通常寫成一個數據類(簡稱類),對一個類進行實例化後得到的是一個數據表(簡稱表)。再次強調與其他語言不同,S#類是程式代碼,S#表是該代碼運行時對應的數據值,這就是所謂的“類”披炫服靚妝化成“表”。
S#第四定律:無名成列表,有名數據表。
用道德經的名言“無名天地之始,有名萬物之母”來描述S#對數據的理解再貼合不過了。上帝創世時的世間萬物還都是無名,但取名這事,還是歸功於人類的聰明才智,為此人類創造了語言。同樣S#語言表達一系列無名的數據集合時採用列表,而表達一系列有名的數據集合時採用的是數據表。可見命名是S#語言表達數據的關鍵方式,也是把數據加工成信息的必經之路。
上面就是S#語言的聖經,如果您對編程語言領域(PL,Programming Language,網上引起很多爭議的王垠就是這方面的專家)有比較深入的研究,本人上述的巨集觀論斷或許會引發您的深思或頓悟。不過不懂沒關係,懵懂也很好,下麵我就會逐步講解。
二、數據表
一個無名的數據值是這樣子(數值):
10
一系列無名的同類數據值是這樣子(數組):
[10, 20, 30]
一系列無名的各類數據值是這樣子(列表):
{'box', 10, 20, 30, true}
一系列有名的各類數據值是這樣子(數據表):
(1)標準寫法
{Name='box', L=10, W=20, H=30, Visible=true}
這種表達讓我們看到了盒子及其長寬高等更多的數據含義,促使原始無意義的數據加工成了有意義的信息。這就是數據表的標準寫法,可用於表達包含一系列鍵值數據對的集合,註意與其他語言不同,數據錶帶有局部變數堆棧,其鍵就是堆棧中的變數名稱,而值就是變數的數據值。
如果每個鍵值都是數組,那麼是不是與資料庫的列對應,數據表也就相當於一張資料庫中的表。關係資料庫的理論已經證明表的關係演算與Lambada演算的表達能力是等價的,可見數據表有多麼重要了。
{ Name=['box1', 'box2', 'box3'] , L=[10, 11, 12] , W=[20, 21 22] , H=[30, 31, 32] , Visible=[true, false, true] }
正因為數據表是如此地重要,S#語言支持很多種數據表的擴展寫法:
(2)JSON寫法
熟悉Javascript的同學有福了,把數據表標準寫法的鍵名寫成字元串,中間符號換成冒號,就成為JSON寫法。例如:
{"Name":'box', "L":10, "W":20, "H":30, "Visible":true}
現在JSON數據在網路上大行其道,而S#語言可以說就是JSON的超集,可以直接讀取JSON,處理JSON數據簡直太簡單、方便和殘暴了。
(3)腳本寫法
熟悉腳本文件的同學有福了,把數據表標準寫法去掉逗號,花括弧換成括弧即可簡化成腳本寫法。例如:
(Name='box' L=10 W=20 H=30 Visible=true)
這種寫法沒有,分隔符,由於S#把換行也看成空白,因此可以很容易直接導入外部常見的各種腳本或配置文本文件,就是加上()直接解析運行即可。這種腳本數據應用也很廣泛,S#語言處理起來也非常簡單、方便和殘暴。
(4)YAML寫法
熟悉YAML和Python的同學有福了,把數據表標準寫法去掉逗號和花括弧,中間符號換成冒號,加上===可擴展成YAML寫法,例如:
=== Name: 'box' Size: L: 10 W: 20 H: 30 Visible: true === //等價於標準寫法 { Name = 'box' , Size = { L = 10 , W = 20 , H = 30 } , Visible = True }
這種寫法沒有,分隔符,換行縮進自動處理成不同層級的嵌套,可以省略掉好多逗號和花括弧,因此表達層級數據非常整齊和簡潔,這點與Python處理數據有點異曲同工之妙。S#語言處理YAML也比較簡單、方便。
除此之外數據表還有很多從類實例化的寫法,本文後面也會專門介紹。簡單的數據表也可以看作資料庫中表的一條記錄,如果有很多條類似這樣的記錄如下:
{Name='box1', L=10, W=20, H=30, Visible=true}
{Name='box2', L=11, W=21, H=31, Visible=false}
那麼說明他們都是同一類型的數據,也就是有共同的模板。這時我們可以使用數據類對他們所屬的分類或模板進行抽象表達——數據類(簡稱類),而實際的數據記錄則可以按照該類進行實例化修改成對應的數據表。無名的數據類就是匿名類,有名的數據類通常通過賦值定義或顯示定義。
三、匿名類
匿名類(也叫表模板、元表或自定義數據類)指數據類定義體(即代碼塊)本身,可以當作變數進行傳遞和使用,使得類成為所謂的“一等公民”。實現方式上也是通過指向類入口的指針、地址或引用傳遞,在程式後面調用匿名類時則把當前程式跳轉到匿名類體上執行,當然每次執行還要處理同名稱變數數據值的傳遞和堆棧進出。
(1)匿名類公式
class 預設數據表
數據表前加class關鍵字就可以定義一個匿名類,可用於變數賦值。例如:
class {Name='box', L=10, W=20, H=30, Visible=true}
(2)繼承匿名類公式
class : 基類名稱 預設數據表
如果類是從指定的基類派生而來,那麼class關鍵字後面指定一個基類名稱即可,實例化的時候是先實例化基類數據再實例化當前類的數據。例如:
class : A {Name='box', L=10, W=20, H=30, Visible=true}
S#類通常是有名字的,上述匿名類的表達方式比較簡單便捷,通常用於公式中使用,複雜的請使用下麵的類定義。
四、類定義
由於類是一等公民了,因此類通常也可以像變數一樣進行賦值定義。
S#有兩種類定義形式,但是其類實例化方法是一樣的。
(1)隱式類定義
變數名稱=匿名類
這種寫法最為靈活多變,可使用在任何公式或語句中。因為匿名類被看作普通數據,可以通過命名變數進行傳遞和使用,無論是傳給其他函數作為實參調用,或是作為其他函數的返回值,都沒有任何違和感覺。例如:
{ f = class {a=10, b=20} , g = f{a=15} , //直接調用,g結果{a=15,b=20} h = { a = f , b = a{b=30} } //變數傳遞後間接調用,b結果{a=10 b=30} }
隱式類定義可以使用在任何變數賦值公式中,而且類變數的作用域還可以用專門語法進行修改。
(2)顯式類定義語句(註:只能使用在語句中)
class 類名稱 預設數據表;
class關鍵字顯示定義一個類名,進行類變數賦值。例如:
class Test {Name='box', L=10, W=20, H=30, Visible=true}
class 類名稱 語句塊
與上面類似,只不過類定義體是語句塊,支持更複雜代碼邏輯,這時和C#的類定義代碼很像。例如:
class Test { var L=10; var W=20; func GetArea() { Return L*W; } }
class 類名稱 : 基類名稱 預設數據表;
class關鍵字顯示定義一個類名,進行派生類變數賦值。例如:
class Test : A {Name='box', L=10, W=20, H=30, Visible=true}
class 類名稱 : 基類名稱 語句塊
同樣類定義體也改成語句塊,可支持更複雜代碼邏輯,這時和C#的派生類定義代碼很像。例如:
class Test : A { var L=10; var W=20; func GetArea() { Return L*W; } }
五、類實例化
一個類其實就是一段代碼,只要進行實例化才能轉化成為數據表進行使用,這與函數必須進行調用後才能轉化為數據值進行使用相類似。
假設前面上下文已定義了類型A如下:
class A { L=10, W=20, Area=L*W }
那麼可以使用以下四種S#的類實例化方式,可以用於任何公式和語句中。
(1)無參數的類實例化公式
類名稱 {}
直接獲得類代碼的運行結果即數據表,註意類實例化後時還會把類名添加到數據表中。例如:
{ Rect = class {L = 10, W = 20, Area = L * W} , b = Rect{} // b結果為 { Class = 'Rect', L = 10 , W = 20 , Area = 200 } }
(2)帶參數的類實例化公式
類名稱 { 參數賦值系列 }
傳入參數數據值並賦值給類代碼中的同名變數,再運行類代碼獲得的結果數據表。註意如果傳入參數沒有找到同名變數,那麼也會添加到結果數據表中,註意類實例化後時還會把類名添加到數據表中。例如:
{ Rect = class {L = 10, W = 20, Area = L * W} , b = Rect{L=4, X=50} // b結果為 { Class = 'Rect', L = 4 , W = 20 , Area = 80, X=50 } }
(3)帶子節點的類實例化公式
類名稱 { 類實例化公式系列 }
運行類代碼並把子節點作為Children變數附加到的結果數據表,註意類實例化後時還會把類名添加到數據表中。例如:
{ Shape = class {Name = ""} , //定義基類 Line = class : Shape {L = 10} , //定義線類 Rect = class : Shape {L = 10, W = 20, Area = L * W} , //定義矩形類 b = Shape //實例化Shape類(帶子節點) { Line{ Name = "l", L = 5 } Rect{ Name = "r", L = 5 } } } //b的計算結果為: { Class = 'Shape', Name = '' , Children = { { Class = 'Line', Name = 'l' , L = 5 } , { Class = 'Rect', Name = 'r' , L = 5 , W = 20 , Area = 100 } } }
(4)帶參數及子節點的類實例化公式
類名稱 { 參數賦值系列 } { 類實例化公式系列 }
傳入參數數據值給類代碼中的同名變數,再運行類代碼並把子節點作為Children變數附加到的結果數據表。註意如果傳入參數沒有找到同名變數,那麼也會添加到結果數據表中,另外類實例化後時還會把類名添加到數據表中。例如:
{ Shape = class {Name = ""} , //定義基類 Line = class : Shape {L = 10} , //定義線類 Rect = class : Shape {L = 10, W = 20, Area = L * W} , //定義矩形類 b = Shape{ Name="l" Extend="擴展數據"} //實例化Shape類(帶參數和子節點) { Line{ Name = "l", L = 5 } Rect{ Name = "r", L = 5 } } } //b的計算結果為: { Class = 'Shape' , Name = 'l' , Extend = '擴展數據' , Children = { { Class = 'Line' , Name = 'l' , L = 5 } , { Class = 'Rect' , Name = 'r' , L = 5 , W = 20 , Area = 100 } } }
六、XML類實例化
S#還支持類似於XML的類實例化方式,與標準方式一一對應且功能等價,也可以用於任何公式和語句中。
(1)無參數的XML類實例化公式
<類名稱/>
與XML相同,例如:
<Rect/>
(2)帶參數的XML類實例化公式
<類名稱 參數賦值系列/>
與XML相同,賦值序列中間用空白而不是逗號分隔,例如:
<Rect L=4 X=50/>
(3)帶子節點的XML類實例化公式
與XML相似,但子節點的寫法不同,這樣便於擴展,例如:
<類名稱/> { 類實例化公式系列 }
<Shape/> { <Line Name = "l" L = 5 /> <Rect Name = "r" L = 5 /> }
(4)帶參數及子節點的XML類實例化公式
<類名稱 參數賦值系列 /> { 類實例化公式系列 }
與XML相似,但子節點的寫法不同,這樣便於擴展,例如:
<Shape Name="l" Extend="擴展數據"/> { <Line Name = "l" L = 5 /> <Rect Name = "r" L = 5 /> }
七、類定義及實例化綜合示例
下麵給出一個有繼承關係的類的語句級別,其實與C#類似,只不過S#更加關註於數據表達層面,不用進行序列化和反序列就能把數據全部計算並表達出來,用於動態擴展各類數據和信息是非常方便的。
{ class Drawing { var Layer = '0'; var Color = 'ByLayer'; var LineType = 'ByLayer'; var LineWidth = 'ByLayer'; var X = 0; var Y = 0; } class Block:Drawing { var Rotation = 0; var Scale = 1; var Children = []; } class Line:Drawing { var Length = 100; var Angle = 45; } class Circle:Drawing { var Radius = 50; } class Rectangle:Drawing { var Width = 100; var Height = 50; } return Drawing { Name = "圖形", Author = "hjx" } { Line { Length = 50 } Circle { Radius = 30 } Block { Rotation = 45 } { Line { Angle = 15 } Circle { Radius = 80 } } }; }
計算結果如下:
{ Class = 'Drawing' , Layer = '0' , Color = 'ByLayer' , LineType = 'ByLayer' , LineWidth = 'ByLayer' , X = 0 , Y = 0 , Name = '圖形' , Author = 'hjx' , Children = { { Class = 'Line' , Layer = '0' , Color = 'ByLayer' , LineType = 'ByLayer' , LineWidth = 'ByLayer' , X = 0 , Y = 0 , Length = 50 , Angle = 45 } , { Class = 'Circle' , Layer = '0' , Color = 'ByLayer' , LineType = 'ByLayer' , LineWidth = 'ByLayer' , X = 0 , Y = 0 , Radius = 30 } , { Class = 'Block' , Layer = '0' , Color = 'ByLayer' , LineType = 'ByLayer' , LineWidth = 'ByLayer' , X = 0 , Y = 0 , Rotation = 45 , Scale = 1 , Children = { { Class = 'Line' , Layer = '0' , Color = 'ByLayer' , LineType = 'ByLayer' , LineWidth = 'ByLayer' , X = 0 , Y = 0 , Length = 100 , Angle = 15 } , { Class = 'Circle' , Layer = '0' , Color = 'ByLayer' , LineType = 'ByLayer' , LineWidth = 'ByLayer' , X = 0 , Y = 0 , Radius = 80 } } } } }
八、S#語言小結
至今為止,本系列博文把S#的基本語言特性大都介紹過了,還有一些高級特性後續博文繼續講解。不知您對S#語言有何看法?如有請把您理解的優勢利弊發表在下麵評論中。
總而言之,S#語言是一種基於.NET平臺的面向表達的動態語言,他儘量兼收並蓄了其他語言常用的語法特性,把數據值、數組、列表、數據表、函數以及數據類全部都看做是一等公民,並通過對公式和語句兩種語法基礎結構的對全面支持和擴展,使得該語言化繁為簡,表達能力相當出色。
聲明:原創文章歡迎轉載,但請註明出處,https://www.cnblogs.com/ShoneSharp。
軟體: S#語言編輯解析運行器13.6.31,運行環境.NET 4.0,綠色軟體,單個EXE直接運行,無副作用。網盤下載鏈接為https://pan.baidu.com/s/1nv1hmJn