当前位置: 首页 > 面试题库 >

协议只能用作一般约束,因为它具有Self或relatedType要求

王弘和
2023-03-14
问题内容

我有一个协议RequestType,它具有如下的relatedType模型。

public protocol RequestType: class {

    associatedtype Model
    var path: String { get set }

}

public extension RequestType {

    public func executeRequest(completionHandler: Result<Model, NSError> -> Void) {
        request.response(rootKeyPath: rootKeyPath) { [weak self] (response: Response<Model, NSError>) -> Void in
            completionHandler(response.result)
            guard let weakSelf = self else { return }
            if weakSelf.logging { debugPrint(response) }
        }
    }

}

现在,我试图对所有失败的请求进行排队。

public class RequestEventuallyQueue {

    static let requestEventuallyQueue = RequestEventuallyQueue()
    let queue = [RequestType]()

}

但是我在线上看到错误,let queue = [RequestType]()因为Protocol
RequestType具有Self或associatedType要求,因此只能用作通用约束。


问题答案:

现在假设我们调整您的协议以添加一个使用关联类型的例程:

public protocol RequestType: class {
    associatedtype Model
    var path: String { get set }

    func frobulateModel(aModel: Model)
}

Swift可以让您RequestType按照自己的方式创建数组。我可以将这些请求类型的数组传递给函数:

func handleQueueOfRequests(queue: [RequestType]) {
    // frobulate All The Things!

    for request in queue {
       request.frobulateModel(/* What do I put here? */)
    }
}

我到了要散布所有东西的地步,但是我需要知道将哪种类型的参数传递给调用。我的某些RequestType实体可以采用LegoModel,有些可以采用PlasticModel,而另一些可以采用PeanutButterAndPeepsModel。Swift对歧义性不满意,因此它不会让您声明具有关联类型的协议变量。

同时,例如,RequestType当我们知道它们所有人都使用时,创建一个数组非常有意义LegoModel。这似乎是合理的,而且确实如此,但是您需要某种表达方式。

一种方法是创建一个将真实类型与抽象Model类型名称相关联的类(或struct或enum):

class LegoRequestType: RequestType {
  typealias Model = LegoModel

  // Implement protocol requirements here
}

现在声明一个数组是完全合理的,LegoRequestType因为如果我们想要frobulate所有这些数组,我们知道我们必须LegoModel每次都传递。

与关联类型的这种细微差别使使用它们的协议变得特别。Swift标准库最著名的协议就是这样的CollectionSequence

为了使您能够创建一组实现Collection协议的事物或一组实现序列协议的事物,标准库采用了一种称为“类型擦除”的技术来创建结构类型AnyCollection<T>AnySequence<T>。要在Stack
Overflow答案中进行解释,类型擦除技术相当复杂,但是如果您在网上搜索,则会有很多关于它的文章。

我可以推荐来自Alex Gallagher的有关YouTube
上具有关联类型协议(PAT)的视频。



 类似资料:
  • 问题内容: 我正在尝试创建一个字典(实际上是HashSet),该字典以Swift中的自定义协议为键,但是它给了我标题错误: 协议“ myProtocol”只能用作通用约束,因为它具有“自我”或相关类型要求 而且我不能做它的正面或反面。 问题答案: 协议从协议继承,而协议又从协议继承。协议具有以下要求: 并且包含在其中某处的协议只能在类型约束中使用,而不能在任何地方使用。 这是一个类似的问题。

  • 这是SWIFT中的有效协议声明: 但这不是: 错误消息为: 协议“proto2”只能用作泛型约束,因为它具有自身或关联的类型要求 因此,当使用作为函数的返回类型时,Swift并不认为这是所定义协议的约束,因此可以使用协议本身作为函数的返回类型。但是当使用作为函数的参数类型时,其行为是完全不同的。 我想知道为什么会有这样的差别?

  • 有没有办法将列约束应用于我的所有网格窗格列。我有各种 GridPane 控件,我希望它们共享以下列的约束: 使用css能做到吗? 编辑 我最终做了这样的事情。但它不起作用(我的列宽调整到74以下),任何线索?

  • 我有一种情况,我在协议中声明了两个函数,其中一个接受可选的一般约束参数,另一个函数不接受参数,但需要在扩展中实现为默认函数,它调用带有参数的函数并传递。但是我得到了这个错误: 传递给不带参数的调用的参数 我的代码: 显然,编译器无法推断出类型。例如,如果我传递一个所需类型的< code > nil (< code > Optional ),那么编译器会很高兴。例如: 有没有一种方法可以在我的默认函

  • 问题内容: 为什么我可以做到这一点而没有任何错误: 虽然我定义了这个: 如果我的协议中的定义大部分被忽略(getter,setter定义),为什么我仍要使用它们? 问题答案: 根据官方文件: 可以通过多种方式通过符合类型来满足吸气剂和设置剂的要求。如果属性声明同时包含get和set关键字,则符合条件的类型可以使用存储的变量属性或既可读又可写的计算属性(即,同时实现getter和setter的)来实

  • 问题内容: 我在Swift上建模所有者/所有者方案: 然后我有一对遵循上述建模类型的教授/学生: 但是我在类中的定义上收到以下错误: 非最终课程(“学生”)无法满足协议“ Ownee”的要求“所有者”,因为它在非参数,非结果类型的位置使用了“自我” 我试图了解导致此错误的原因,为什么将类定为final可以解决该问题,以及是否存在一些解决方法能够以不同的方式对此模型进行建模而不将其定为final。我