【问题标题】:How do I disambiguate this call to a generic function with a function parameter in Swift?如何在 Swift 中消除对带有函数参数的泛型函数的调用的歧义?
【发布时间】:2020-10-29 06:57:39
【问题描述】:

我正在编写一个解析器类,它希望以特定顺序读取一系列标记。其语法中的某些产品具有可选的非终端,因此我想做一个通用的“可能”函数,可以将负责将非终端解析为回调的函数传递给该函数。通常,该函数会在失败时抛出错误,但由于在某些情况下它是可选的,因此该 may 函数会抑制错误。但是,Swift 提供了错误“表达式类型在没有更多上下文的情况下不明确”,我无法找出正确的强制转换和/或类型来消除歧义。

这是我能够编写的用于重现错误的最少代码量:

public struct VariableDeclaration {
    public let identifier: Identifier
    public let type: String?
}

public struct Identifier { }

public class Parser {
    
    public func parseVariableDeclaration() throws -> VariableDeclaration {
        let identifier = try self.parseIdentifier()
        let type = self.maybe(self.parseType)
        return VariableDeclaration(identifier: identifier, type: type)
    }
    
    public func parseIdentifier() throws -> Identifier { return Identifier() }
    
    public func parseType() throws -> String { return "" }
    
    public func maybe<T>(_ callback: (Parser) -> () throws -> T) -> T? {
        do {
            return try callback(self)()
        }
        catch {
            return nil
        }
    }
}

以下是我在消除有问题的行时的一些失败尝试:

let type: String? self.maybe(self.parseType)
let type = self.maybe(self.parseType) as String?
let type = self.maybe<String>(self.parseType)

【问题讨论】:

    标签: swift generics ambiguous


    【解决方案1】:

    这里的问题不是泛型参数。您的第一次和第二次尝试会告诉编译器 T 应该是什么类型。

    问题是您作为callback 传递的值,它具有以下签名:

    (Parser) -> () throws -> T
    

    您传入的self.parseType 具有以下签名:

    () throws -> String
    

    使用Self.parseType(注意大写S)或Parser.parseType作为callback的值会起作用。

    或者,您可以像这样定义maybe

    public func maybe<T>(_ callback: (Parser) throws -> T) -> T? {
        do {
            return try callback(self)
        } catch {
            return nil
        }
    }
    

    然后这样称呼它:

    let type = self.maybe { try $0.parseType() }
    

    【讨论】:

    • 我无法让Self.parseType 编译(它拒绝将Self 转换为Parser),但Parser.parseType 工作成功。 lambda 建议也有效。感谢您的详尽回复。
    • @Jared 啊,那是因为Parser 是一个(非最终)类。所以子类中的Self 不会是(确切的)Parser...
    【解决方案2】:

    我不确定这是否真的是你想要做的,但如果你想保留maybe的签名,你需要像这样传递方法的部分引用:

            let type = self.maybe(Parser.parseType)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-03
      相关资源
      最近更新 更多