Давайте предположим, что у меня есть протокол Parser
, определенный следующим образом:
protocol Parser {
associatedtype Element
associatedtype Stream
func parse(_ stream: Stream) -> (Element, Stream)?
}
Теперь давайте приведем этот протокол в соответствие со следующей структурой:
struct CharacterParser: Parser {
let character: Character
func parse(_ stream: String) -> (Character, String)? {
guard stream.first == character
else { return nil }
return (character, String(stream.dropFirst()))
}
}
Теперь мы можемнапишите аккуратное расширение Character
для создания синтаксических анализаторов:
extension Character {
var parser: CharacterParser { return CharacterParser(character: self) }
}
let p = Character("a").parser
print(p.parse("abc"))
// Prints `Optional(("a", "bc"))`
Теперь предположим, что я хочу скрыть специфику реализации синтаксического анализатора и использовать новые непрозрачные типы из Swift 5.1. Компилятор позволит мне написать следующее:
@available(OSX 10.15.0, *)
extension Character {
var parser: some Parser { return CharacterParser(character: self) }
}
Пока все хорошо. Но теперь нет способа вызвать parse(:)
, так как кажется, что компилятор больше не может разрешить тип аргумента, который я должен предоставить. Другими словами, следующее не будет компилироваться:
let p = Character("a").parser
print(p.parse("abc"))
// error: Cannot invoke 'parse' with an argument list of type '(String)'
Единственное решение, которое я нашел, было определить «более конкретный» протокол, который наследуется от Parser
, например, StringParser
, который устанавливает связанныйвведите ограничение того же типа. К сожалению, мне не особенно нравится этот подход, так как я чувствую, что он не будет хорошо масштабироваться, если бы я определил другие методы, возвращающие Parser
экземпляры с более сложными ограничениями типов. Другими словами, я бы торговал, выставляя определенные типы (например, SomeSpecificParserType
), выставляя определенные протоколы (например, SomeSpecificParserProtocol
), тогда как я хотел бы остаться на более высоком уровне абстракции, в идеале, чтобы иметь дело только с some Parser
возвращаемыми типами.
Можно ли каким-либо образом предоставить дополнительную информацию, чтобы указать, что связанный тип возвращаемого из свойства типа * String
исключительно для определения свойства, так что Swift может позднее вывести конкретный тип p.parse
* * 1030