今天读的这篇博文,做者是一名 Haskell 程序员,从 Swift 枚举类能够经过 rawValue
来初始化这个特性谈起,提出了一些本身的观点,摘录一部分以下:html
I always thought of the
rawValue
mechanism as an escape hatch to drop back down to the world of Objective-C, rather than something you should use in Swift if you can help it. I don't want to say that usingrawValue
is wrong in any way, but rather that it doesn't fit with my intuition. Years of Haskell programming have warped my brain in interesting ways. One important lesson I've learned is that designing the right types for your problem is a great way to help the compiler debug your program.git
感兴趣的同窗建议直接阅读原文:The Design of Types。因为是一边看着老罗的直播一边写的,因此写的可能有点凌乱哈哈哈哈。程序员
输入校验你们应该都不陌生,为了防止 SQL 注入之类的问题,一般会对输入的内容进行校验。简单来讲咱们能够定义一个函数进行校验:github
func sanitize(userInput : String) -> String
每次须要校验输入的时候用这个函数过滤一下就行。数据库
但问题也随之而来:当出现一个字符串的时候,须要咱们手动判断是否须要进行校验,一不当心可能会校验屡次 (好比获取的时候校验了,写入数据库又校验了,这有点糟糕),也有可能就没校验 (好比获取的时候觉得写入的时候会校验,写入数据库的时候觉得已经校验过了,这更糟糕)。swift
为了不这种繁琐的问题,咱们可让编译器去作这个工做:api
typealias UserInput = String struct SanitizedString { let value : String init(input : UserInput) { value = sanitize(input) } }
能够看到咱们定义了两个新的类型 SanitizedString
和 UserInput
:less
UserInput
就是 String 类型,用来标记用户的输入。SanitizedString
是结构体,经过一个 value
存储校验后的字符串。是的,这样就不用亲自监控输入的校验了,使用起来看看。好比咱们经过 sanitize
把空格去掉而后返回:函数
import Foundation func sanitize(userInput : String) -> String { return userInput.stringByReplacingOccurrencesOfString(" ", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil) } typealias UserInput = String struct SanitizedString { let value : String init(input : UserInput) { value = sanitize(input) } } var a: SanitizedString = SanitizedString(input: " Hello WHY ") println(a.value) // HelloWHY
咱们能够用个元组来封装用户信息,好比存储了邮件地址和脸书帐号:post
typealias UserInfo = (EmailAddress?, FacebookAccount?)
可是很不幸,这样定义的类型会出现这种无效值:
let bogus : UserInfo = (nil, nil)
文中提出了这样一个观点:应该让非法状态不可表述。换句话说,若是咱们想避免这种既没有邮箱地址也没有脸书帐号的状况出现,应该让这种状况没法表现出来。
好比咱们能够用这样一个枚举类型来表示用户的状态:
enum UserInfo { case Email (EmailAddress) case Facebook (FacebookAccount) case EmailAndFacebook (EmailAddress, FacebookAccount) }
用户的信息分为三种状况:
看起来增长了不少额外的工做量,却也收获了不少。咱们能够把一部分业务逻辑分离出来。
好比移除脸书帐号,若是用元组的方式进行删除是这样的:
func removeFacebookInfo(userInfo : (EmailAddress?, FacebookAccount?)) -> (EmailAddress?, FacebookAccount?) { return (userInfo.0, nil) }
用枚举类型来解决则能够返回可选类型表示移除失败的状况:
func removeFacebookInfo(userInfo : UserInfo) -> UserInfo? { switch userInfo { case let .EmailAndFacebook(email,_): return UserInfo.Email(email) default: return nil } }
对于类型的设计,做者分享一段不错的代码 routes.swift :
import Foundation enum Github { case Zen case UserProfile(String) } protocol Path { var path : String { get } } extension Github : Path { var path: String { switch self { case .Zen: return "/zen" case .UserProfile(let name): return "/users/\(name)" } } } let sample = Github.UserProfile("ashfurrow") println(sample.path) // Prints "/users/ashfurrow" // So far, so good protocol Moya : Path { var baseURL: NSURL { get } var sampleData: String { get } // Probably JSON would be better than AnyObject } extension Github : Moya { var baseURL: NSURL { return NSURL(string: "https://api.github.com")! } var sampleData: String { switch self { case .Zen: return "Half measures are as bad as nothing at all." case .UserProfile(let name): return "{login: \"\(name)\", id: 100}" } } } func url(route: Moya) -> NSURL { return route.baseURL.URLByAppendingPathComponent(route.path) } println(url(sample)) // prints https://api.github.com/users/ashfurrow
相关文章在这里:Type-safe URL routes in Swift。就不展开讨论了。
做者对于如何合理有效的利用 Swift 的特性进行了思考和讨论,值得一看。
感受写总结很费时间,由于本身写的没有原文好,又没时间展开讨论只能匆匆记录下来。下次尝试写成英文的锻炼一下英语能力吧。。。