我已经在stackoverflow上检查了关于这个问题的所有答案,但仍然无法弄清楚如何解决这个问题.我的模型看起来像这样
protocol Commandable: Equatable {
var condition: Condition? {get set}
func execute() -> SKAction
}
Run Code Online (Sandbox Code Playgroud)
以及实施该协议的3个结构
struct MoveCommand: Commandable {
var movingVector: CGVector!
//MARK: - Commandable
var condition: Condition?
func execute() -> SKAction {
...
}
}
extension MoveCommand {
// MARK:- Equatable
static func ==(lhs: MoveCommand, rhs: MoveCommand) -> Bool {
return lhs.movingVector == rhs.movingVector && lhs.condition == rhs.condition
}
}
Run Code Online (Sandbox Code Playgroud)
struct RotateCommand: Commandable {
var side: RotationSide!
// MARK: - Commandable
var condition: Condition?
func execute() -> SKAction {
...
}
}
extension RotateCommand {
// MARK: - Equatable
static func ==(lhs: RotateCommand, rhs: RotateCommand) -> Bool {
return lhs.side == rhs.side && lhs.condition == rhs.condition
}
}
Run Code Online (Sandbox Code Playgroud)
当我尝试创建具有[Commandable]数组的第三个结构时,问题就开始了:
struct FunctionCommand: Commandable {
var commands = [Commandable]()
Run Code Online (Sandbox Code Playgroud)
编译器输出:Protocol 'Commandable' can only be used as a generic constraint because it has Self or associated type requirements.然后我用这种方式重写了我的结构:
struct FunctionCommand<T : Equatable>: Commandable {
var commands = [T]()
Run Code Online (Sandbox Code Playgroud)
我解决了这个问题但是出现了新的问题.现在我无法FunctionCommand使用旋转和移动命令的实例创建,只能使用其中一个实例:(:
let f = FunctionCommand(commands: [MoveCommand(movingVector: .zero, condition: nil),
RotateCommand(side: .left, condition: nil)], condition: nil)
Run Code Online (Sandbox Code Playgroud)
任何帮助,将不胜感激.
更新:那篇文章帮助我弄清楚了 - https://krakendev.io/blog/generic-protocols-and-their-shortcomings
你需要做的是使用类型擦除,就像AnyHashable在Swift标准库中一样.
你做不到:
var a: [Hashable] = [5, "Yo"]
// error: protocol 'Hashable' can only be used as a generic constraint because it has Self or associated type requirements
Run Code Online (Sandbox Code Playgroud)
你要做的是使用类型擦除类型AnyHashable:
var a: [AnyHashable] = [AnyHashable(5), AnyHashable("Yo")]
a[0].hashValue // => shows 5 in a playground
Run Code Online (Sandbox Code Playgroud)
所以,你的解决办法是在更小的部分先被分割的协议,推动Equatable以Hashable(重用AnyHashable)
protocol Conditionable {
var condition: Condition? { get set }
}
protocol Executable {
func execute() -> SKAction
}
protocol Commandable: Hashable, Executable, Conditionable {}
Run Code Online (Sandbox Code Playgroud)
然后创建一个AnyCommandable结构,如下所示:
struct AnyCommandable: Commandable, Equatable {
var exeBase: Executable
var condBase: Conditionable
var eqBase: AnyHashable
init<T: Commandable>(_ commandable: T) where T : Equatable {
self.condBase = commandable
self.exeBase = commandable
self.eqBase = AnyHashable(commandable)
}
var condition: Condition? {
get {
return condBase.condition
}
set {
condBase.condition = condition
}
}
var hashValue: Int {
return eqBase.hashValue
}
func execute() -> SKAction {
return exeBase.execute()
}
public static func ==(lhs: AnyCommandable, rhs: AnyCommandable) -> Bool {
return lhs.eqBase == rhs.eqBase
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以像这样使用它:
var a = FunctionCommand()
a.commands = [AnyCommandable(MoveCommand()), AnyCommandable(FunctionCommand())]
Run Code Online (Sandbox Code Playgroud)
并且您可以轻松访问属性commands,因为AnyCommandable实现Commandable
a.commands[0].condition
Run Code Online (Sandbox Code Playgroud)
您需要记住现在添加Hashable和Equatable所有命令.我使用这些实现进行测试:
struct MoveCommand: Commandable {
var movingVector: CGVector!
var condition: Condition?
func execute() -> SKAction {
return SKAction()
}
var hashValue: Int {
return Int(movingVector.dx) * Int(movingVector.dy)
}
public static func ==(lhs: MoveCommand, rhs: MoveCommand) -> Bool {
return lhs.movingVector == rhs.movingVector
}
}
struct FunctionCommand: Commandable {
var commands = [AnyCommandable]()
var condition: Condition?
func execute() -> SKAction {
return SKAction.group(commands.map { $0.execute() })
}
var hashValue: Int {
return commands.count
}
public static func ==(lhs: FunctionCommand, rhs: FunctionCommand) -> Bool {
return lhs.commands == rhs.commands
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1336 次 |
| 最近记录: |