gpt4 book ai didi

protocols - 具有不总是使用的属性的 Swift 协议(protocol)

转载 作者:行者123 更新时间:2023-12-05 02:20:20 27 4
gpt4 key购买 nike

这是这个问题的后续:Can I have a Swift protocol without functions

假设我想向我的协议(protocol)添加更多属性:

protocol Nameable {
var name: String {get}
var fullName: String: {get}
var nickName: String: {get}
}

但是,并非每个符合此协议(protocol)的结构都可能具有全名和/或昵称。我该怎么做?我可以使这两个属性以某种方式可选吗?或者我可能需要三个独立的协议(protocol)?或者我只是将它们添加到每个结构中,但将它们留空,如下所示:

struct Person : Nameable {
let name: String
let fullName: String
let nickName: String
let age: Int
// other properties of a Person
}

let person = Person(name: "Steve", fullName: "", nickName: "Stevie", age: 21)

可以编译并工作,但我不知道这是否是“正确”的方法?

最佳答案

与 Objective-C 不同,您不能在纯 Swift 中定义可选协议(protocol)要求。符合协议(protocol)的类型必须采用所有指定的要求。

允许可选属性要求的一种潜在方法是将它们定义为可选属性,并使用仅返回 nil 的计算属性的默认实现。

protocol Nameable {
var name : String? { get }
var fullName : String? { get }
var nickname : String? { get }
}

extension Nameable {
var name : String? { return nil }
var fullName : String? { return nil }
var nickname : String? { return nil }
}

struct Person : Nameable {

// Person now has the option not to implement the protocol requirements,
// as they have default implementations that return nil

// What's cool is you can implement the optional typed property requirements with
// non-optional properties – as this doesn't break the contract with the protocol.
var name : String
}

let p = Person(name: "Allan")
print(p.name) // Allan

然而,这种方法的缺点是您可能会使用它们未实现的属性(在本例中为 fullNamenickName)污染符合类型。

因此,如果一个类型具有这些属性在逻辑上是没有意义的(比如你想让 City 符合 Nameable——但城市(真的)没有昵称),你不应该让它符合 Nameable

如您所说,更灵活的解决方案是定义多个协议(protocol)来定义这些要求。这样,类型就可以准确地选择他们想要实现的要求。

protocol Nameable {
var name : String { get }
}

protocol FullNameable {
var fullName : String { get }
}

protocol NickNameable {
// Even types that conform to NickNameable may have instances without nicknames.
var nickname : String? { get }
}

// A City only needs a name, not a fullname or nickname
struct City : Nameable {
var name : String
}

let london = City(name: "London")

// Person can have a name, full-name or nickname
struct Person : Nameable, FullNameable, NickNameable {
var name : String
var fullName: String
var nickname: String?
}

let allan = Person(name: "Allan", fullName: "Allan Doe", nickname: "Al")

你甚至可以使用 protocol composition为了方便起见,定义一个 typealias 来表示所有这三种协议(protocol),例如:

typealias CombinedNameable = Nameable & FullNameable & NickNameable

struct Person : CombinedNameable {
var name : String
var fullName: String
var nickname: String?
}

关于protocols - 具有不总是使用的属性的 Swift 协议(protocol),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39550646/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com