Я пытаюсь представить вызов функции, чтобы я мог создать небольшой язык сценариев для создания игр. Сейчас я просто пытаюсь настроить интерфейсы между всеми протоколами и классами, которые мне нужны. У меня есть класс, FunctionCall<T>
. У него есть метод execute()
, который выполняет текущую функцию и возвращает экземпляр типа T?
. FunctionCall
также имеет массив экземпляров типа FunctionCall
для представления любых параметров. Он также имеет поле stringRepresentation
, которое представляет собой строковое представление вызова функции, которое вводит пользователь. Эта строка может быть что-то вроде createNode(named: myCircle)
или, в базовом случае, это может быть просто литерал, как myCircle
. Для ясности, myCircle
в этом случае - String
. Я, вероятно, решу не использовать кавычки вокруг String
s на моем небольшом языке сценариев.
Моя проблема связана с методом 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
}
}