swift – 具有通用类型的协议功能

swift – 具有通用类型的协议功能,第1张

概述我想创建一个如下所示的协议: protocol Parser { func parse() -> ParserOutcome<?>}enum ParserOutcome<Result> { case result(Result) case parser(Parser)} 我想要有解析器返回特定类型的结果或另一个解析器. 如果我在Parser上使用关联类型,那么我不能 我想创建一个如下所示的协议:
protocol Parser {    func parse() -> ParserOutcome<?>}enum ParserOutcome<Result> {    case result(Result)    case parser(Parser)}

我想要有解析器返回特定类型的结果或另一个解析器.

如果我在Parser上使用关联类型,那么我不能在枚举中使用Parser.如果我在parse()函数中指定一个通用类型,那么我不能在没有泛型类型的实现中定义它.

我该如何实现?

使用泛型,我可以写这样的东西:

class Parser<Result> {    func parse() -> ParserOutcome<Result> { ... }}enum ParserOutcome<Result> {    case result(Result)    case parser(Parser<Result>)}

这样一来,Parser将被结果类型参数化. parse()可以返回Result类型的结果,也可以返回输出Result类型结果的任何类型的解析器,或返回由相同Result类型参数化的另一个解析器.

然而,关联类型,据我所知,我总是有一个自我约束:

protocol Parser {    associatedtype Result    func parse() -> ParserOutcome<Result,Self>}enum ParserOutcome<Result,P: Parser where P.Result == Result> {    case result(Result)    case parser(P)}

在这种情况下,我不能有任何类型的解析器返回相同的Result类型,它必须是相同类型的解析器.

我想使用Parser协议获得与通用定义相同的行为,我希望能够在类型系统的范围内执行此 *** 作,而不会引入新的Boxed类型,就像我可以使用正常的通用定义.

在我看来,定义相关类型OutcomeParser:Parser协议中的Parser,然后返回由该类型参数化的枚举将解决问题,但是如果我尝试以这种方式定义OutcomeParser,我会收到错误:

Type may not reference itself as a requirement

我不会如此快速地将类型删除作为“黑客”或“围绕[类型系统”工作] – 实际上我认为它们与类型系统一起工作,以提供一个有用的层在使用协议(并且已经提及的标准库本身使用例如 AnySequence,AnyIndexAnyCollection)时的抽象.

正如你所说,你在这里所做的一切都有可能从一个解析器返回一个给定的结果,或是使用相同结果类型的另一个解析器.我们不关心该解析器的具体实现,我们只想知道它有一个返回相同类型的结果的parse()方法,或者具有相同要求的另一个解析器.

类型擦除对于这种情况是完美的,因为所有您需要做的是引用给定的解析器的parse()方法,允许您抽取掉该解析器的其余实现细节.重要的是要注意,您不会在此丢失任何类型的安全性,因此您根据需要指定的方式与解析器的类型完全相同.

如果我们看一个类型删除的解析器AnyParser的潜在实现,希望你会看到我的意思:

struct AnyParser<Result> : Parser {    // A reference to the underlying parser's parse() method    private let _parse : () -> ParserOutcome<Result>    // Accept any base that conforms to Parser,and has the same Result type    // as the type erasure's generic parameter    init<T:Parser where T.Result == Result>(_ base:T) {        _parse = base.parse    }    // Forward calls to parse() to the underlying parser's method    func parse() -> ParserOutcome<Result> {        return _parse()    }}

现在在ParserOutcome中,您可以简单地指定解析器大小写具有关联值AnyParser< Result>即可以使用给定的Result通用参数的任何类型的解析实现.

protocol Parser {    associatedtype Result    func parse() -> ParserOutcome<Result>}enum ParserOutcome<Result> {    case result(Result)    case parser(AnyParser<Result>)}...struct barParser : Parser {    func parse() -> ParserOutcome<String> {        return .result("bar")    }}struct FooParser : Parser {    func parse() -> ParserOutcome<Int> {        let nextParser = barParser()        // error: Cannot convert value of type 'AnyParser<Result>'        // (aka 'AnyParser<String>') to expected argument type 'AnyParser<_>'        return .parser(AnyParser(nextParser))    }}let f = FooParser()let outcome = f.parse()switch outcome {case .result(let result):    print(result)case .parser(let parser):    let nextOutcome = parser.parse()}

从这个例子可以看出,Swift仍然执行类型安全.我们试图在一个AnyParser类型的擦除包装器中包装一个barParser实例(与Strings一起使用),该包装器需要一个Int泛型参数,导致编译器错误.一旦FooParser被参数化以使用Strings而不是Int,则编译器错误将被解析.

事实上,由于AnyParser在这种情况下只能作为单一方法的包装器,另一个潜在的解决方案(如果真的憎恶类型的擦除)就是直接使用它作为ParserOutcome的关联值.

protocol Parser {    associatedtype Result    func parse() -> ParserOutcome<Result>}enum ParserOutcome<Result> {    case result(Result)    case anotherParse(() -> ParserOutcome<Result>)}struct barParser : Parser {    func parse() -> ParserOutcome<String> {        return .result("bar")    }}struct FooParser : Parser {    func parse() -> ParserOutcome<String> {        let nextParser = barParser()        return .anotherParse(nextParser.parse)    }}...let f = FooParser()let outcome = f.parse()switch outcome {case .result(let result):    print(result)case .anotherParse(let nextParse):    let nextOutcome = nextParse()}
总结

以上是内存溢出为你收集整理的swift – 具有通用类型的协议功能全部内容,希望文章能够帮你解决swift – 具有通用类型的协议功能所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1028481.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-23
下一篇 2022-05-23

发表评论

登录后才能评论

评论列表(0条)

保存