如何强制通过Swift中的字符串解析作为参数传入的类?

时间:2019-01-09 18:09:51

标签: swift generics protocols

我试图表示一个函数调用,以便我可以编写一些脚本语言来创建游戏。现在,我只是想在我需要的所有协议和类之间建立接口。我有一堂课,FunctionCall<T>。它具有方法execute(),该方法执行当前函数并返回类型为T?的实例。 FunctionCall还具有一组FunctionCall类型的实例数组,以表示任何参数。它还有一个字段stringRepresentation,它是用户将输入的函数调用的字符串表示形式。该字符串可能类似于createNode(named: myCircle),或者在基本情况下,可能只是一个文字,例如myCircle。需要明确的是,在这种情况下,myCircleString。我可能会选择不使用我的小脚本语言在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
    }
}

1 个答案:

答案 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}}用作通用约束,就可以了。