JSON的三個未知特性

fango發表於2014-05-29

眾所周知JSON是JavaScript的資料交換格式——簡單但卻封閉且不可靠。

例如JSON並未定義時間格式。沒有統一的標準使得交換不再可靠。你說2014/1/5是一月五號還是五月一號?還有雖然JSON“定義”了數字很像C或Java的number,但實際實現的只有JavaScript的浮點數。這樣C或Java的兩個不同的整數,例如 9007199254740992 和 9007199254740993 使用JSON交換後竟然相等。

JSON只有七種格式:真假空數句表格。其中真true假false空null三個代表就佔了七席中的約一半,可它們除了自己什麼都不代表。數number可以是不大不小的整數或者不一定準的科學計數。句string是一串只用一對雙引號夾住的統一碼Unicode、但又沒有明確是統一在UTF8/16/32還是其他的標準下。表object用於名值對照,例如寫成{"name":{"true":null,"false":true}}用來代表一個有名真空假亦真的物件。格array也是表,只是不稱名字叫號碼,[3.14159,2.71828,1.618]三個號子關的分別是圓周率π尤拉數e和黃金分割φ的近似值。

儘管JSON是JavaScript的物件,但JavaScript的物件不一定是JSON。不符合條件的一大堆,比如名字是單引號的不行,沒有引號的也不行;比如JSON必須是表格,單獨的真假空數句統統不行。最大的侷限在於,JSON對如何規定統一的規定沒有任何的規定,這就必須靠交換雙方私下裡有些協議,例如雙方同意的交換必須包括sex而不能叫gender,名字必須是UUID而不能具實名等等。如果能夠在JSON格式中把這些潛規則明確下來,例如用{"protocol":"GB/1984","sex":"you","name":"me"},則雙方都會知道這是個違規的交易。

我在使用中發現,其實有三個未加說明的特效能極大提高JSON的效能。

第一,詞 symbol,不需要用引號標註也不必是字母數字。例如 i,=,you,? 是四個用逗號分隔的詞。

第二,貼 tag,是#開頭的詞,用來定義規則。例如 #GB/1984 是上面交易雙方自己的規則;#inst 是符合RFC-3339的一個時間點,例如 #inst "1970-10-04-T01:02:03.04Z"; #uuid 是8-4-4-4-12格式的32個隨機16進位制通用唯一碼。

第三,例 list。除了使用花括號方括號的表格,我們還可以用圓括號括起一系列的詞。例如 (print,3)。括號裡的第一個位置是方式function,作用於後面列出的其他數值。除了內部的一些方式,我們也可以使用 defn 定義自己的方式。例如 (defn,forever,[],(forever)),這樣我們就多了一種方式可以完成堆疊溢位StackOverflow。如果逗號太扎眼,我們完全可以為之省略。

我們可以使用 if 加以判斷,並分別規定真假用例。例如 (if nil true false) 是假的,因為 if 把所有不是 nil 不是 false 的都當真。這樣我們就可以寫些有用的方式,例如計算 n! 的公式:

(defn factorial [n] (if (= n 1) 1 (* n (factorial (- n 1)))

天,這不是 LISP 是什麼?!

(注,本文啟發自http://www.jayway.com/2013/04/01/three-undocumented-features-of-json-3/)

(又注,這不是 LISP,是借 JSON 引入 Clojure 和 EDN。第12期碼農的97頁也有介紹。)

相關文章