swift - 如何为具有类型约束的泛型函数提供默认参数?

标签 swift string compiler-errors

以下函数定义是合法的 Swift:

func doSomething<T: StringProtocol>(value: T = "abc") {
    // ...
}

编译器能够确定默认参数 "abc" 是一个 String,并且 String 符合 StringProtocol.

但是这段代码无法编译:

func doSomething<T: Collection>(value: T = "abc") where T.Element == Character {
    // ...
}

编译错误:

Default argument value of type 'String' cannot be converted to type 'T'

似乎编译器拥有与第一种情况一样多的信息来确定 String 确实可以转换为 T。此外,如果我删除默认参数并使用相同的值调用该函数,它会起作用:

doSomething(value: "abc")

能否以不同的方式编写此函数,以便我可以提供默认的 String 参数?这是 Swift 的局限性,还是我心智模型的局限性?

最佳答案

重要的约束是T: ExpressibleByStringLiteral。这就是允许从字符串文字初始化某些东西的原因。

func doSomething<T: Collection>(value: T = "abc")
    where T.Element == Character, T: ExpressibleByStringLiteral {
    // ...
}

正如 Leo Dabus 所说,T.Element == Character 在技术上不是必需的,但删除它会改变含义。仅仅因为某个东西是一个集合并且可以用字符串文字初始化并不意味着它的元素是字符。

还值得注意的是,虽然所有这些都是可能的,但通常是糟糕的 Swift IMO。 Swift 没有任何方式来表达默认的 type 是什么,所以 doSomething() 在所有这些情况下都会导致“无法推断通用参数‘T’”。

IMO 的正确解决方案是重载,它避免了所有这些问题:

func doSomething<T: StringProtocol>(value: T) {
}

func doSomething() {
    doSomething(value: "abc")
}

这允许您使默认参数不仅仅是“可以用文字 “abc” 初始化的东西”,而是您真正的意思:默认值是字符串“abc”。

通常,默认参数只是重载的便利,因此您通常可以用缺少该参数的显式重载替换任何默认参数。

关于swift - 如何为具有类型约束的泛型函数提供默认参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55431977/

相关文章:

Swift 2,协议(protocol)扩展和 respondsToSelector

swift - 如何将核心数据输出到数组中以生成图形(Swift)

c# - 在 C# 中反转字符串的最佳方法

c++ - 静态库 API 问题(std::string 与 char*)

C 结构示例,编译期间出错

swift - 删除 NSAttributedString : "Type of expression is ambiguous without more context"

php - 使用 PHP 在 Swift 中接收 POST

swift - 从单例中获取可选字符串

c++ - 对象的链表?

function - FORTRAN 95 在使用函数和函数中的预期形式参数列表时出现主程序错误