首页 > 解决方案 > 如何在 Swift 中消除对带有函数参数的泛型函数的调用的歧义?

问题描述

我正在编写一个解析器类,它期望以特定顺序读取一系列标记。其语法中的某些产品具有可选的非终端,因此我想做一个通用的“可能”函数,可以将负责将非终端解析为回调的函数传递给该函数。通常,该函数会在失败时抛出错误,但由于在某些情况下它是可选的,因此该 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)

标签: swiftgenericsambiguous

解决方案


这里的问题不是通用参数。您的第一次和第二次尝试会告诉编译器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() }

推荐阅读