我试图表示一个函数调用,以便我可以编写一些脚本语言来创建游戏。现在,我只是想在我需要的所有协议和类之间建立接口。我有一堂课,FunctionCall<T>
。它具有方法execute()
,该方法执行当前函数并返回类型为T?
的实例。 FunctionCall
还具有一组FunctionCall
类型的实例数组,以表示任何参数。它还有一个字段stringRepresentation
,它是用户将输入的函数调用的字符串表示形式。该字符串可能类似于createNode(named: myCircle)
,或者在基本情况下,可能只是一个文字,例如myCircle
。需要明确的是,在这种情况下,myCircle
是String
。我可能会选择不使用我的小脚本语言在String
周围使用引号。
我的问题是使用execute()
方法。我想返回一个T
类型的实例。到目前为止,我已经考虑过强制T
符合协议(我们将其称为Parseable
),该协议强制其具有采用String
并返回类型实例的方法T
。我用这种方法发现的问题是我无法创建这样的方法,因为我没有办法从协议中引用将要实现协议的类型。换句话说,如果T为SKShapeNode
,则无法从SKShapeNode
内部引用Parseable
,因此我可以指示返回类型必须为SKShapeNode
。我发现的另一种方法是使Parseable
具有一个需要的初始化器,该初始化器采用String
。这在结构体实现协议但不适用于类时起作用。当我尝试在类中实现协议时遇到的问题是该类要我创建初始化器required
,但是我不能这样做,因为我无法放置required
初始化器在扩展程序中。
我希望FunctionCall
类看起来像这样
class FunctionCall<T: Parseable> {
var parameters = [FunctionCall]()
var stringRepresentation: String!
init(stringRepresentation: String) {
self.stringRepresentation = stringRepresentation
}
func execute() -> T? {
guard let indexOfFirstLeftParen = stringRepresentation.firstIndex(of: "("),
let indexOfLastRightParen = stringRepresentation.lastIndex(of: ")") else {
// then this is a literal value, because no function is being called
return T(string: stringRepresentation)
}
// TODO: implement
return nil
}
}
答案 0 :(得分:3)
我发现这种方法的问题是我无法创建这样的方法,因为我没有办法从协议内部引用将要实现协议的类型。
实际上,可以使用Self
来解决该问题,// I think this is a better name
protocol ConvertibleFromString {
static func from(string: String) -> Self?
}
// implementation
extension Int : ConvertibleFromString {
static func from(string: String) -> Int? {
return Int(string)
}
}
指的是任何符合条件的类型:
final class SKSpriteNodeFinal : SKSpriteNode, ConvertibleFromString {
static func from(string: String) -> SKSpriteNodeFinal? {
...
}
}
对于非最终类,您必须创建一个最终子类,如下所示:
var foo: ConvertibleFromString? = nil // error
请注意,这会阻止您的协议用作变量的类型:
ConvertibleFromString
但是我不认为这会成为问题,因为您仅将{{1}}用作通用约束,就可以了。