多层次深层通用/协议的Swift通用和协议问题

时间:2018-06-29 14:37:40

标签: ios swift generics swift3

我正计划为芝加哥儿童制作一个闪存卡应用程序,只要他们能够遵循相同的协议,就可以提出很多问题。理想情况下,会有许多不同难度的游戏,并且视图将能够使用所有游戏,因为所有游戏都遵循相同的协议。我希望每个转弯都有能力采用完全不同的结构,只要它是相等的即可。

我觉得我已经接近了,但是我无法终生解决如何让游戏获取任何数据而又不会出错的感觉……我觉得我已经接近了,但是可以不能超过这个减速带。

我不断收到错误消息,例如“ TurnDefinable只能用作通用约束,因为它具有Self或associate类型要求”

protocol GameDefinable {
    associatedtype TurnType: TurnDefinable
    var turns: [TurnType] { get }
}

class Game<T: TurnDefinable>: GameDefinable {
    var turns: [T]

    init(turns: [T]) {
        self.turns = turns
    }
}

class Turn<A: AnswerDefinable>: TurnDefinable {
    var question: String
    var correctAnswer: A
    var answers: [A]

    init(question: String, answers: [A], correctAnswer: A) {
        self.question = question
        self.answers = answers
        self.correctAnswer = correctAnswer
    }
}

protocol TurnDefinable {
    associatedtype AnswerType
    /// Localized string to ask the user a question they must answer
    var question: String { get }
    /// Array of possible answers
    var answers: [AnswerType] { get }
    /// Correct answer per turn
    var correctAnswer: AnswerType { get }
}

protocol AnswerDefinable: Equatable {
    // Will have more stuff here like localized formatted string, etc
}

// Just created this test pretending our answers will be Ints
struct ExampleOfAnAnswerStruct: AnswerDefinable {
    static func == (lhs: ExampleOfAnAnswerStruct, rhs: ExampleOfAnAnswerStruct) -> Bool {
        return lhs.testInteger == rhs.testInteger
    }

    // Just created this to get the equatable
    var testInteger = 0
}


struct ExampleOfAnAnswerStruct2: AnswerDefinable {
    var string: String
    static func == (lhs: ExampleOfAnAnswerStruct2, rhs: ExampleOfAnAnswerStruct2) -> Bool {
        return lhs.string == rhs.string
    }
}

任何帮助都会非常感激...

编辑:我现在离我们更近了,我只需要弄清楚如何使用两个具有不同答案类型的回合

let turnExample1 = Turn<ExampleOfAnAnswerStruct>(question: "Which is the lonliest number?", answers: [ExampleOfAnAnswerStruct(testInteger: 1), ExampleOfAnAnswerStruct(testInteger: 2), ExampleOfAnAnswerStruct(testInteger: 3)], correctAnswer: ExampleOfAnAnswerStruct(testInteger: 1))
let turnExample2 = Turn<ExampleOfAnAnswerStruct2>(question: "You say goodbye, and i say ...", answers: [ExampleOfAnAnswerStruct2(string: "hello"), ExampleOfAnAnswerStruct2(string: "goodbye")], correctAnswer: ExampleOfAnAnswerStruct2(string: "hello"))

let testGame = Game(turns: [turnExample1, turnExample2])

我好亲近!感谢到目前为止的所有帮助!

2 个答案:

答案 0 :(得分:0)

我有个主意,但我不确定。

如果泛型类的两个实例化都使用相同的类型(例如整数),则它们只有相同的类型。 在协议中具有associatedType可能意味着一个实例不能与另一个实例相同地使用。

使用TurnDefinable意味着两个实例化可以具有不同的类型,并且编译器可能不希望数组中具有不同的类型(不可用)。
无法使用,因为您不能一视同仁,调用相同的函数,访问相同的变量。
具有不同功能签名的功能不再是同一功能。

如果编译器只是忽略以下内容,您将如何编写?

for turn in turns {
    turn.answers.first!.X // ???
}

您可以使用一个空的Answer协议并在其上键入switch。也许有帮助。

protocol Answer {}

for turn in turns {
    for answer in turn.answers {
        switch answer {
        case let type1 = answer as AnswerType1:
            break //
        case let type2 = answer as AnswerType2:
            break
        default:
            fatalError("Answer type unknown \(type(of: Answer))")
        }
    }
}

答案 1 :(得分:0)

您不能拥有类型为TurnDefinable的数组,因为您已经看到它是具有关联类型的协议。

您需要调整GameDefinable协议,使其具有自己的关联类型,可以将其用作数组的类型:

protocol GameDefinable {
    associatedtype TurnType: TurnDefinable
    var turns: [TurnType] { get }
}

然后,您可以在Game类中添加一个通用参数,该通用参数将用作GameDefinable协议的关联类型(您也可以跳过该通用参数,并使用特定类型声明数组例如Turn<ExampleOfAnAnswerStruct>(如果您想将游戏限制为某种类型)

class Game<T: TurnDefinable>: GameDefinable {
    var turns: [T]

    init(turns: [T]) {
        self.turns = turns
    }
}