Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 使用通用约束_Swift_Generics_Swift Protocols - Fatal编程技术网

Swift 使用通用约束

Swift 使用通用约束,swift,generics,swift-protocols,Swift,Generics,Swift Protocols,我知道以前有人问过这个问题,但我不知道如何解决当前的问题。我已使用associatedtype属性定义了协议MultipleChiceProblem: protocol Questionable { var text: String {get set} var givenAnswer: String? {get set} } protocol MultipleChoiceQuestionable: Questionable { associatedtype Value

我知道以前有人问过这个问题,但我不知道如何解决当前的问题。我已使用associatedtype属性定义了协议MultipleChiceProblem:

protocol Questionable {
    var text: String {get set}
    var givenAnswer: String? {get set}
}

protocol MultipleChoiceQuestionable: Questionable {
    associatedtype Value
    var answers: Value { get }
}

struct OpenQuestion: Questionable {
    var text: String
    var givenAnswer: String?
}

struct MultipleChoiceQuestion: MultipleChoiceQuestionable {
    typealias Value = [String]
    var text: String
    var givenAnswer: String?
    var answers: Value
}

struct NestedMultipleChoiceQuestion: MultipleChoiceQuestionable {
    typealias Value = [MultipleChoiceQuestion]
    var text: String
    var answers: Value
    var givenAnswer: String?
} 
符合此协议的类型保存在数组中,如下所示:

在我的代码中,我想做一些类似的事情:


这是不可能的,因为Xcode警告我:Protocol MultipleChiiceProblem只能用作通用约束。我一直在寻找如何解决这个问题,因为泛型对我来说是很新的。显然,Swift在编译时不知道associatedtype的类型,这就是引发此错误的原因。我读过关于使用类型擦除的文章,但我不知道这是否解决了我的问题。也许我应该使用泛型属性,或者我的协议定义错误

如果要应用于子协议对象的操作不依赖于关联的类型,即既没有泛型参数也不返回泛型类型,则可以引入一个仅公开所需属性/方法的辅助协议,让您的类型符合该协议,并根据协议声明问题

例如,如果您只想了解有关该问题的一些信息:

protocol MultipleChoiceInfo {
  var numberOfAnswers: Int { get }
}

extension MultipleChoiceQuestion: MultipleChoiceInfo {
  var numberOfAnswers: Int { return answers.count }
}
// do the same for the other multiple-choice types
然后,您可以通过新协议访问问题,如下所示:

let question = questions[index]
if let info = question as? MultipleChoiceInfo {
  print(info.numberOfAnswers)
}
正如我所说,如果您不能提供抽象的非泛型接口,那么这将不起作用

编辑

如果您需要处理问题中的通用数据,您可以根据具体的通用类型将逻辑提取到另一个处理类型中,该处理类型为您的问题提供接口。然后,每个问题类型将其数据发送到处理器接口:

protocol MultipleChoiceProcessor {
  func process(stringAnswers: [String])
  func process(nestedAnswers: [MultipleChoiceQuestion])
}

protocol MultipleChoiceProxy {
  func apply(processor: MultipleChoiceProcessor)
}

extension MultipleChoiceQuestion: MultipleChoiceProxy {
  func apply(processor: MultipleChoiceProcessor) {
    processor.process(stringAnswers: answers)
  }
}
只需创建一个符合MultipleChiceProcessor的类型,然后再次执行类型检查:

if let proxy = question as? MultipleChoiceProxy {
  proxy.apply(processor:myProcessor)
}

顺便说一句,如果您的实际应用程序中没有更多的协议和结构,那么您也可以完全放弃协议内容。。。对于此类问题,它似乎有点设计过度。

谢谢您的回复!这个辅助协议非常棒,我以前从未见过这样的设计模式。问题是我真的需要这个answers属性,它不能在这个辅助协议中定义。。但也许我应该在我的问题中更好地提到这一点,对此我很抱歉。我说这个问题没有其他解决办法,对吗?如果是这样,我将不得不重新思考架构。再次感谢!即使您的用例可以在没有协议的情况下以更简单的方式解决,但这是一个了解非协议协议的好例子:当然还有另一个解决方案。。。我编辑了我的答案。
protocol MultipleChoiceProcessor {
  func process(stringAnswers: [String])
  func process(nestedAnswers: [MultipleChoiceQuestion])
}

protocol MultipleChoiceProxy {
  func apply(processor: MultipleChoiceProcessor)
}

extension MultipleChoiceQuestion: MultipleChoiceProxy {
  func apply(processor: MultipleChoiceProcessor) {
    processor.process(stringAnswers: answers)
  }
}
if let proxy = question as? MultipleChoiceProxy {
  proxy.apply(processor:myProcessor)
}