对于使用“some”指令返回的 var,类型特定方法不可用
Type specific method is unavailable for a var returned with `some` directive
考虑工厂方法模式实现:
import UIKit
protocol TransportProtocol: CustomStringConvertible {
func techReview()
}
// Make default implemetation opposed to @objc optional methods and properties
extension TransportProtocol {
func techReview() {
print("Reviewing \(type(of: self))")
}
var description: String {
"This is a \(type(of: self))"
}
}
final class Car: TransportProtocol {
func changeOil() {
print("Changed oil")
}
}
final class Ship: TransportProtocol {
}
protocol LogisticProtocol {
associatedtype Transport: TransportProtocol
func createTransport() -> Transport
func delivery(from A: Any, to B: Any)
func techRewiew(for transport: TransportProtocol)
}
extension LogisticProtocol {
func delivery(from A: Any, to B: Any) {
print("Moving \(type(of: self)) from \(A) to \(B)")
}
func techRewiew(for transport: TransportProtocol) {
transport.techReview()
}
}
final class RoadLogistics: LogisticProtocol {
func createTransport() -> some TransportProtocol {
Car()
}
}
final class SeaLogistics: LogisticProtocol {
func createTransport() -> some TransportProtocol {
Ship()
}
}
// Usage:
class Client {
// ...
static func someClientCode<L: LogisticProtocol>(creator: L) -> some TransportProtocol {
let transport = creator.createTransport()
print("I'm not aware of the creator's type, but it still works.\n"
+ transport.description + "\n")
creator.delivery(from: "Source", to: "Destination")
return transport
}
// ...
}
let someTransport = Client.someClientCode(creator: RoadLogistics())
type(of: someTransport.self) // Car
someTransport.changeOil() // Error: Value of type 'some TransportProtocol' has no member 'changeOil'
问题是如果编译器知道它是 Car
而不仅仅是 TransportProtocol
,为什么我不能在 someTransport
上调用 changeOil()
。
我们可以从使用 some
指令中获得什么好处,而不仅仅是裸协议类型?
方法的return类型是some TransportProtocol
,不是Car
。因此,即使 returned 实例的类型为 Car
,您也不能调用任何仅存在于 Car
上但不存在于 TransportProtocol
.[=25= 上的方法]
运行时知道someTransport
的具体类型是Car
,但是编译器只知道return 类型符合 TransportProtocol
.
如果您希望能够访问 someTransport
上的 Car
方法,您需要将其向下转换为 Car
.
if let car = someTransport as? Car {
car.changeOil()
}
使用 some
关键字在用于不透明 returns 类型时有 type-system 好处(作为 Swift 5.1 的一部分在 SE-0244 中引入),因为它实际上启用了 returning 具有关联类型的协议,而不必显式地使该方法通用。这就是驱动 SwiftUI 的原因,因为它使您能够 return some View
.
另一方面,对没有关联类型的协议使用不透明 return 类型没有任何好处,因此在您的特定示例中,没有理由使用它。
考虑工厂方法模式实现:
import UIKit
protocol TransportProtocol: CustomStringConvertible {
func techReview()
}
// Make default implemetation opposed to @objc optional methods and properties
extension TransportProtocol {
func techReview() {
print("Reviewing \(type(of: self))")
}
var description: String {
"This is a \(type(of: self))"
}
}
final class Car: TransportProtocol {
func changeOil() {
print("Changed oil")
}
}
final class Ship: TransportProtocol {
}
protocol LogisticProtocol {
associatedtype Transport: TransportProtocol
func createTransport() -> Transport
func delivery(from A: Any, to B: Any)
func techRewiew(for transport: TransportProtocol)
}
extension LogisticProtocol {
func delivery(from A: Any, to B: Any) {
print("Moving \(type(of: self)) from \(A) to \(B)")
}
func techRewiew(for transport: TransportProtocol) {
transport.techReview()
}
}
final class RoadLogistics: LogisticProtocol {
func createTransport() -> some TransportProtocol {
Car()
}
}
final class SeaLogistics: LogisticProtocol {
func createTransport() -> some TransportProtocol {
Ship()
}
}
// Usage:
class Client {
// ...
static func someClientCode<L: LogisticProtocol>(creator: L) -> some TransportProtocol {
let transport = creator.createTransport()
print("I'm not aware of the creator's type, but it still works.\n"
+ transport.description + "\n")
creator.delivery(from: "Source", to: "Destination")
return transport
}
// ...
}
let someTransport = Client.someClientCode(creator: RoadLogistics())
type(of: someTransport.self) // Car
someTransport.changeOil() // Error: Value of type 'some TransportProtocol' has no member 'changeOil'
问题是如果编译器知道它是 Car
而不仅仅是 TransportProtocol
,为什么我不能在 someTransport
上调用 changeOil()
。
我们可以从使用 some
指令中获得什么好处,而不仅仅是裸协议类型?
方法的return类型是some TransportProtocol
,不是Car
。因此,即使 returned 实例的类型为 Car
,您也不能调用任何仅存在于 Car
上但不存在于 TransportProtocol
.[=25= 上的方法]
运行时知道someTransport
的具体类型是Car
,但是编译器只知道return 类型符合 TransportProtocol
.
如果您希望能够访问 someTransport
上的 Car
方法,您需要将其向下转换为 Car
.
if let car = someTransport as? Car {
car.changeOil()
}
使用 some
关键字在用于不透明 returns 类型时有 type-system 好处(作为 Swift 5.1 的一部分在 SE-0244 中引入),因为它实际上启用了 returning 具有关联类型的协议,而不必显式地使该方法通用。这就是驱动 SwiftUI 的原因,因为它使您能够 return some View
.
另一方面,对没有关联类型的协议使用不透明 return 类型没有任何好处,因此在您的特定示例中,没有理由使用它。