对于使用“some”指令返回的 var,类型特定的方法不可用
考虑工厂方法模式实现:
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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
该方法的返回类型是
some TransportProtocol
,而不是Car
。因此,即使返回的实例是Car
类型,您也无法调用仅存在于Car
上而不存在于TransportProtocol
上的任何方法。运行时知道
someTransport
的具体类型是Car
,但编译器只知道返回类型符合到传输协议
。如果您希望能够访问
someTransport
上的Car
方法,则需要将其向下转换为Car
。使用
some
关键字在用于不透明返回类型时具有类型系统优势(在 SE-0244 作为 Swift 5.1 的一部分),因为它实际上可以返回具有关联类型的协议,而无需必须显式地使该方法通用。这就是驱动 SwiftUI 的原因,因为它使您能够返回一些视图
。另一方面,对没有关联类型的协议使用不透明返回类型没有任何好处,因此在您的特定示例中,没有理由使用它。
The return type of the method is
some TransportProtocol
, notCar
. So even though the returned instance is of typeCar
, you cannot call any methods on it that only exist onCar
, but not onTransportProtocol
.The runtime knows that the concrete type of
someTransport
isCar
, but the compiler only knows that the return type conforms toTransportProtocol
.If you want to be able to access
Car
methods onsomeTransport
, you need to downcast it toCar
.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 returnsome 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.