iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 4
0
Software Development

每天 Racket 3 分鐘系列 第 13

(struct iron-man (day title)) (define today (iron-man 'day-12 "Racket 的資料抽象 — Struct"))

  • 分享至 

  • twitterImage
  •  

1. 有時候你不一定需要物件導向

雖然標題這麼下,但 Racket 的確有物件導向!今明兩天,我們要介紹 Racket 的抽象機制,包含它的資料抽象機制:Struct 與物件導向。

想像一下,我們為什麼需要資料抽象?我們已經有 HashTable 了,或簡單點,也有 List、Vector 了,為什麼需要更高層次地對資料進行抽象處理呢?

我們來看範例程式:

(struct student (id name gender))

(define racket (student 1 "Racket" 'M))
(define julia (student 2 "Julia" 'F))
(define ada (list 3 "Ada" 'F))
(define haskell (hash id 3 name "Haskell Curry" gender 'M))

(student? racket) ;; #t
(student? ada)  ;; #f
(student? haskell) ;; #f
(list? ada)  ;; #t
(list? julia)  ;; #f
(hash? haskell)  ;; #t
(hash? racket) ;; #f

(student-name racket)  ;; "Racket"
(student-gender julia) ;; 'F

我們在此定義了一個簡單的 struct — student,並且宣告了 racket、julia 為 student struct,並且宣告兩個不太合群的 adahaskell (寫這兩個語言的人別生氣唷),一個為 list,一個為 hash

我們定義完了之後,在下方看到使用 student? 直接進行比較,有別於 list?hash?,後者是使用通用型資料結構進行資料的組織,而前者卻是具有 語義 的資料型態。這就是我們所說,資料抽象化之後的作用。

因此,當你把你的資料轉成 struct,它可以擁有自己的語義與存取方式,如第三段程式碼一般。

2. 資料與資料也有繼承關係

Racket 可是很具有現代感的語言呢!struct 可以有繼承關係,例如以下範例:

(struct position (x y))
(struct 3d-position position (z))

(define point (3d-position 1 2 3))

(3d-position-x point)  ;; 錯誤!
(position-x point)  ;; 1
(3d-position-z point)  ;; 3

第一段程式可以看到,我們先定義了 position,再定義了另一個 3d-position,名稱的後頭接著要繼承的 position3d-position 就能繼承 position 的內容。

但是,能否透過 3d-position 來存取 position 的內容呢?在 Racket 的原則裡,是不行的!要存取 position 的內容(xy)還是要透過 position 才可以!

3. 微妙的 equal

那麼,資料之間怎麼比較呢?在 Racket 裡頭,有 eaual?eq?eqv? 等不同的比較方式,我們現在討論最常見的 equal?,可以參考以下範例:

(struct position-t (x y) #:transparent)
(struct position (x y))

(define pos-t1 (position-t 1 2))
(define pos-t2 (position-t 1 2))

(define pos-1 (position 1 2))
(define pos-2 (position 1 2))

(equal? pos-1 pos-t1)  ;; #f
(equal? pos-1 pos-2)  ;; #f
(equal? pos-t1 pos-t2)  ;; #t

我們在這裡定義了兩個很類似的 struct,一個有宣告 #:transparent,一個沒有。然而各位可以看到,第一個 equal? 理所當然地拿到了個 #f,但第二個為什麼是 #f 呢?而第二個 #f 但在第三個 equal? 比較時,卻又是 #t

在這裡閉上眼思考思考,程式語言給予的這個資料抽象機制,它不只讓你可以定義具有語義與結構的資料型態,更具有保護資料內部狀態的封裝性。因此,每個 struct 都是預設為 不透明的 狀態(opaque),外部的 equal? 無法直接取得它的內容以進行比較,操作這個資料的人,只能透過這個資料提供的方式來存取它。反之,就是 透明的 (transparent)狀態,equal? 在外部,可以對 struct 的內容進行比較。

既然這資料,具自己的語義與函式群,也具有封裝性,若它能加上行為,那就更有趣了。我們下回要談到的,就是物件導向了!


上一篇
(hash 'day-11 "為你的資料命名 — Racket 的 Hash")
下一篇
(send day-13 set-title! "Racket 也有物件導向 — Class 與 Object")
系列文
每天 Racket 3 分鐘17
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言