以下函数定义是合法的Swift:
func doSomething<T: StringProtocol>(value: T = "abc") {
// ...
}
编译器能够确定默认参数"abc"
是a String
,并且String
符合StringProtocol
。
但是,此代码无法编译:
func doSomething<T: Collection>(value: T = "abc") where T.Element == Character {
// ...
}
编译器错误:
类型'String'的默认参数值不能转换为类型'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没有任何方法来表示默认类型,因此doSomething()
在所有这些情况下,都会导致“无法推断出通用参数'T'”。
IMO的正确解决方案是过载,它避免了所有这些问题:
func doSomething<T: StringProtocol>(value: T) {
}
func doSomething() {
doSomething(value: "abc")
}
这使您不仅可以使默认参数成为“可以用文字初始化的东西”,还可以使"abc"
您真正的意思是:默认值是字符串“ abc”。
通常,默认参数只是重载的便利,因此您通常可以用缺少该参数的显式重载替换任何默认参数。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句