做者:Natasha,原文連接,原文日期:2016/01/13
譯者:bestswifter;校對:saitjr;定稿:千葉知風編程
Swift 最棒的特色之一就是它內置了對總體結構的不可變性的支持,這使得咱們的代碼更加整潔、安全(關於這個話題,若是還沒看過這篇文章,那麼強烈推薦給你)。swift
不過,真的須要用到可變性時,你應該怎麼作呢?安全
舉個例子,我有一個井字棋棋盤,如今須要改變棋盤上某個位置的狀態:函數式編程
struct Position { let coordinate: Coordinate let state: State enum State: Int { case X, O, Empty } } struct Board { let positions: [Position] // 須要添加一個函數來更新這個位置的狀態 // 狀態從 Empty 改成 X 或者 0 }
若是徹底採用函數式編程的作法,你只須要簡單的返回一個新的棋盤便可:函數
struct Board { let positionsMatrix: [[Position]] init() { // 初始化一個空棋盤的邏輯 } // 函數式編程的作法 func boardWithNewPosition(position: Position) -> Board { var positions = positionsMatrix let row = position.coordinate.row.rawValue let column = position.coordinate.column.rawValue positions[row][column] = position return Board(positionsMatrix: positions) } }
我更傾向於使用這種函數式的作法,由於它不會有任何反作用。變量能夠繼續保持不可變狀態,固然,這樣也很是易於測試!測試
class BoardTests: XCTestCase { func testBoardWithNewPosition() { let board = Board() let coordinate = Coordinate(row: .Middle, column: .Middle) let initialPosition = board[coordinate] XCTAssertEqual(initialPosition.state, Position.State.Empty) let newPosition = Position(coordinate: coordinate, state: .X) let newBoard = board.boardWithNewPosition(newPosition) XCTAssertEqual(newBoard[coordinate], newPosition) } }
不過這種作法並不是在全部場景下都是最佳選擇。翻譯
假設我須要統計每一個用戶贏了多少局井字棋,那麼我建立了一個 Counter:code
struct Counter { let count: Int init(count: Int = 0) { self.count = count } // 須要實現一個增長計數的方法 }
我依然能夠選擇函數式的作法:接口
struct Counter { let count: Int init(count: Int = 0) { self.count = count } // 函數式作法 func counterByIncrementing() -> Counter { let newCount = count + 1 return Counter(count: newCount) } }
不過,若是你真的嘗試了使用這個函數來增長計數,代碼會是這樣:rem
var counter = Counter() counter = counter.counterByIncrementing()
這種寫法不夠直觀,可讀性也不高。因此在這種場景下,我更傾向於使用 mutating
關鍵字:
struct Counter { // 這個變量如今得聲明成 var var count: Int init(count: Int = 0) { self.count = count } // 使用 mutating 關鍵字的作法 mutating func increment() { count += 1 } }
我不喜歡這個函數帶來的反作用,可是相對於可讀性的提高而言,這樣作是值得的:
var counter = Counter() counter.increment()
更進一步來講,經過使用私有 setter 方法能夠確保 count
變量不會被外部修改(由於它如今被聲明爲變量了)。這樣,使用變異方法和變量所帶來的負面影響能夠被降到最低。
在選擇使用 mutating
關鍵字和函數式編程時,我傾向於後者,但前提是不會以犧牲可讀性爲代價。
寫測試是一種很好的檢查接口的方法,它能夠判斷你的函數式編程是否真的有意義。若是你以爲代碼比較奇怪並且不夠直觀,那麼就換成 mutating 方法吧。只要記得使用變量的私有 setter 方法就好了。
本文由 SwiftGG 翻譯組翻譯,已經得到做者翻譯受權,最新文章請訪問 http://swift.gg。��法是否知足預期。若是你以爲接口寫起來很怪異、不直觀,那就去換一種方式去實現吧!最後別忘了用私有
setter
設置你的內部變量哦!
本文由 SwiftGG 翻譯組翻譯,已經得到做者翻譯受權,最新文章請訪問 http://swift.gg。