作者:KHANLOU峭弟,原文鏈接瞒瘸,原文日期:2016-03-18
譯者:Prayer情臭;校對(duì):shanks赌蔑;定稿:千葉知風(fēng)
在我正在做的一個(gè)項(xiàng)目中,有大量關(guān)于度量單位的處理跷乐。(或許我應(yīng)該繼續(xù)去推進(jìn)項(xiàng)目進(jìn)展而不是在這兒寫這篇博客)
我總是覺得對(duì)度量單位的建模是一件很有意思的事情愕提。比如說浅侨,時(shí)間單位如输,假設(shè)你有一個(gè) API 接受一個(gè)時(shí)間作為參數(shù)央勒,可能需要以秒作為單位(又或者是毫秒作為單位)但是订歪,有的時(shí)候你有需要以小時(shí)為單位來表達(dá)時(shí)間刷晋,例如 2 小時(shí)眼虱。所以,為了避免魔數(shù)(magic number) (7200
兩小時(shí)轉(zhuǎn)換為秒為單位)撞蚕,你會(huì)使用 2 * 60 * 60
过牙,為了增加可讀性還會(huì)在其中的操作符之間加上空格。
然而刀疙,7200 這個(gè)數(shù)字并沒有什么實(shí)際意義谦秧。如果你對(duì)著這個(gè)數(shù)字看很長時(shí)間疚鲤,擁有很好的數(shù)學(xué)計(jì)算功底的話集歇,有可能你會(huì)猜到這個(gè)數(shù)字代表著兩個(gè)小時(shí)包含的秒數(shù)桶略。然而如果不是整數(shù)個(gè)小時(shí)換算成秒的話,你可能永遠(yuǎn)也猜不出來鬼悠。
在你的應(yīng)用中删性,7200 這個(gè)魔數(shù)不斷的傳遞和使用亏娜,這個(gè)數(shù)字的度量單位是什么將變得越來越不清晰焕窝。
我們需要使用一種方式,將整數(shù)和元數(shù)據(jù)的信息關(guān)聯(lián)起來维贺。將類型描述為度量單位 這篇文章有過相關(guān)的討論它掂,但是我們能否解決不同單位的度量問題,并且使用類型來描述呢溯泣?如果這樣的話虐秋,當(dāng)我們用 2 小時(shí)加上 30 分鐘的時(shí)候,就不會(huì)得到 32 這樣無意義的結(jié)果垃沦。
(當(dāng)然客给,也有一些語言層面解決這個(gè)問題的方案,但是大多數(shù)的語言不支持這樣的操作)
我們?nèi)匀幌M軌蛴?2 個(gè)小時(shí)加上 30 分鐘,并且得到一個(gè)有意義的結(jié)果坑匠,所以在我們的類型系統(tǒng)中夹纫,Time
需要是一個(gè)度量實(shí)體,同時(shí) Hours
和 Seconds
也需要是。
表示 Time
的可以有多個(gè)單位桶错,這些單位都必須能夠以秒的方式來度量粪狼。
swif
protocol Time {
var inSeconds: Double { get }
}
每個(gè)時(shí)間的單位類型都是獨(dú)立的,但是都需要遵守 Time 協(xié)議。
struct Hours: Time {
let value: Double
var inSeconds: Double {
return value * 3600
}
}
struct Minutes: Time {
let value: Double
var inSeconds: Double {
return value * 60
}
}
我們可以使用同樣的方式來定義 Seconds
澜术,Days
盒延,Weeks
等等結(jié)構(gòu)體,需要注意的是,如果時(shí)間單位過大趋厉,將會(huì)損失一些精度。
現(xiàn)在我們理解了度量單位的刻畫方式乡数,我們可以來進(jìn)行一些度量單位的計(jì)算了罩润。
func + (lhs: Time, rhs: Time) -> Time {
return Seconds(value: lhs.inSeconds + rhs.inSeconds)
}
我們還可以加上一些好用的擴(kuò)展:
extension Time {
var inMinutes: Double {
return inSeconds / 60
}
var inHours: Double {
return inMinutes / 60
}
}
為系統(tǒng)的 Int
類型加上類似 DSL 的擴(kuò)展,代碼思路是從 ActiveSupport 中借鑒的:
extension Int {
var hours: Time {
return Hours(value: Double(self))
}
var minutes: Time {
return Minutes(value: Double(self))
}
}
利用我們的類型系統(tǒng),我們可以寫出短小但是表意明確的代碼:
let total = 2.hours + 30.minutes
(當(dāng)然結(jié)果是以 Seconds
為單位表示的扎筒,可能我們希望引入一個(gè)表示層來將這個(gè)結(jié)果以更加有意義的方式展現(xiàn)給用戶奥溺。我在做的那個(gè)項(xiàng)目中有這方面的工作层亿,不過是用 JavaScript 寫的,不支持這樣的類型系統(tǒng)洞慎,就少了很多樂趣)
本文由 SwiftGG 翻譯組翻譯鸟妙,已經(jīng)獲得作者翻譯授權(quán),最新文章請(qǐng)?jiān)L問 http://swift.gg。