在 Swift 中使用 Protocol 作为函数参数

很短的文章 TL;DR 作者完全就是在卖萌

有一些事情在 Python 中很简单:

class Person:  
    def __init__(self, name):
        self.name = name

def changeName(named, newName):  
    named.name = newName

nick = Person('Nicholas')  
nick.name # => 'Nicolas'

changeName(nick, 'Nicole')  
nick.name # => 'Nicole'  

同样 Ruby 中也非常简单:

class Person  
  attr_accessor :name
  def initialize(name)
    @name = name
  end
end

def changeName(named, newName)  
  named.name = newName
end

nick = Person.new('Nicholas')  
nick.name # => "Nicholas"

changeName(nick, 'Nicole')  
nick.name # => "Nicole"  

但在 Swift 中实现起来并不简单,所幸对于类(class)我们还有协议(protocol)

  • 声明一个只能由类继承的协议
  • 使用协议作为函数的参数类型
protocol Named: class {  
    var name: String { get set }
}

class Person: Named {  
    var name: String

    init(name: String) {
        self.name = name
    }
}

func changeName(named: Named, newName: String) {  
    named.name = newName
}

let nick = Person(name: "nick")  
changeName(nick, newName: "NICK")  
print(nick.name) // "NICK"  

如果不想仅限于类,让 changeName 函数同样适用于结构体,可以这样做:

  • 声明一个泛型函数,使用类型 T 遵循协议 Named
  • 参数 T 必须是一个 inout 参数,用于之后能被修改(因为结构体是值传递)
  • 所有的参数必须是 var 不能是 let
protocol Named {  
    var name: String { get set }
}

class Person: Named {  
    var name: String

    init(name: String) {
        self.name = name
    }
}

struct Pet: Named {  
    var name: String
}

func changeName<T: Named>(inout named: T, toName newName: String) {  
    named.name = newName
}

var nick = Person(name: "nick")  
changeName(&nick, toName: "NICK")  
print(nick.name) // "NICK"

var maru = Pet(name: "Maru")  
changeName(&maru, toName: "Hana")  
print(maru.name) // "Hana"  

就这样,我们没有使用继承,也能够让 changeName 更加通用


-EOF-

如果感觉此文对你有帮助,请随意打赏支持作者 😘

chengway

认清生活真相之后依然热爱它!

Subscribe to Talk is cheap, Show me the world!

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!