对于使用“some”指令返回的 var,类型特定的方法不可用

发布于 2025-01-15 17:19:24 字数 2091 浏览 3 评论 0原文

考虑工厂方法模式实现:

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,为什么我不能在 someTransport 上调用 changeOil()不仅仅是一个TransportProtocol。 使用 some 指令,而不仅仅是纯粹的协议类型,我们可以获得什么好处吗?

Consider a factory method pattern implementation:

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'

The question is why I can't call changeOil() on someTransport if the compiler knows it is a Car not just a TransportProtocol.
Are there any benefits we can get from using some directive, not just bare protocol types?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

相思故 2025-01-22 17:19:24

该方法的返回类型是 some TransportProtocol,而不是 Car。因此,即使返回的实例是 Car 类型,您也无法调用仅存在于 Car 上而不存在于 TransportProtocol 上的任何方法。

运行时知道someTransport的具体类型是Car,但编译器只知道返回类型符合到传输协议

如果您希望能够访问 someTransport 上的 Car 方法,则需要将其向下转换为 Car

if let car = someTransport as? Car {
    car.changeOil()
}

使用 some 关键字在用于不透明返回类型时具有类型系统优势(在 SE-0244 作为 Swift 5.1 的一部分),因为它实际上可以返回具有关联类型的协议,而无需必须显式地使该方法通用。这就是驱动 SwiftUI 的原因,因为它使您能够返回一些视图

另一方面,对没有关联类型的协议使用不透明返回类型没有任何好处,因此在您的特定示例中,没有理由使用它。

The return type of the method is some TransportProtocol, not Car. So even though the returned instance is of type Car, you cannot call any methods on it that only exist on Car, but not on TransportProtocol.

The runtime knows that the concrete type of someTransport is Car, but the compiler only knows that the return type conforms to TransportProtocol.

If you want to be able to access Car methods on someTransport, you need to downcast it to Car.

if let car = someTransport as? Car {
    car.changeOil()
}

Using the some keyword has type-system benefits when used for opaque returns types (introduced in SE-0244 as part of Swift 5.1), since it actually enables returning a protocol with associated types without having to explicitly make the method generic. This is what drives SwiftUI, since it enables you to return some View.

On the other hand, using opaque return types for protocols without associated types holds no benefits, so in your particular example, there's no reason to use it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文