我正在尝试创建一个可以采用可选参数的泛型函数。 这是我到目前为止所做的:
func somethingGeneric<T>(input: T?) {
if (input != nil) {
print(input!);
}
}
somethingGeneric("Hello, World!") // Hello, World!
somethingGeneric(nil) // Errors!
如图所示,它适用于String
,但不适用于nil
。
将其与nil
一起使用会产生以下两个错误:
error: cannot invoke 'somethingGeneric' with an argument list of type '(_?)'
note: expected an argument list of type '(T?)'
我做错了什么以及如何正确声明/使用此功能?另外,我希望尽可能简化函数的使用(我不想做nil as String?
之类的事情。)
答案 0 :(得分:5)
我想编译器无法弄清T
来自nil
的内容。
以下工作正常,例如:
somethingGeneric(Optional<String>.None)
答案 1 :(得分:2)
我认为你永远不会调用somethingGeneric(nil)
,但主要是somethingGeneric(value)
或somethingGeneric(function())
,编译器有足够的信息不会被试图猜测类型:
func somethingGeneric<T>(input: T?) {
if let input = input {
print(input);
}
}
func neverString() -> String? {
return nil
}
let a: String? = nil
somethingGeneric("Hello, World!") // Hello, World!
somethingGeneric(a) // Nothing and no error
somethingGeneric(neverString()) // Nothing and no error
另外,我会使用if let
语法而不是if(value != nil)
。
答案 2 :(得分:1)
我明白了:
func somethingGeneric<T>(input: T?) {
if (input != nil) {
print(input!);
}
}
func somethingGeneric(input: NilLiteralConvertible?) {}
somethingGeneric("Hello, World!") // Hello, World!
somethingGeneric(nil) // *nothing printed*
somethingGeneric(nil as String?) // *nothing printed*
答案 3 :(得分:1)
我相信你通过要求能够传递无类型nil
(实际上并不存在;甚至nil
有一个类型)来使问题过于复杂。虽然您的答案中的方法似乎有效,但由于可选促销,它允许创建??
类型。你经常会很幸运,但是我看到它以令人沮丧的方式爆炸,并且调用了错误的功能。问题是String
可以隐式提升为String?
,String?
可以隐式提升为String??
。当隐私地显示??
时,几乎总会出现混淆。
正如MartinR指出的那样,您的方法对于调用哪个版本并不是非常直观。 UnsafePointer
也是NilLiteralConvertible
。因此,推断将调用哪个函数是很棘手的。 “棘手的理由”使它成为令人困惑的错误的可能来源。
您的问题存在的唯一时间是您传递文字nil
。正如@Valentin指出的那样,如果您传递的变量恰好是是 nil
,那么就没有问题;你不需要特殊情况。为什么强制调用者传递无类型的nil
?让呼叫者什么都不通过。
我假设somethingGeneric
在传递nil
的情况下做了一些真正有趣的事情。如果不是这样的话;如果您显示的代码表示实际功能(即所有内容都包含在if (input != nil)
检查中),那么这不是问题。只是不要打电话给somethingGeneric(nil)
;这是一个可证明的无操作。只需删除代码行即可。但我会假设有一些“其他工作。”
func somethingGeneric<T>(input: T?) {
somethingGeneric() // Call the base form
if (input != nil) {
print(input!);
}
}
func somethingGeneric() {
// Things you do either way
}
somethingGeneric("Hello, World!") // Hello, World!
somethingGeneric() // Nothing
答案 4 :(得分:1)
好问答。我有一个Swift 4更新贡献:
var str: String? = "Hello, playground"
var list: Array<String>? = ["Hello", "Coder256"]
func somethingGeneric<T>(_ input: T?) {
if (input != nil) {
print(input!);
}
}
func somethingGeneric(_ input: ExpressibleByNilLiteral?) {}
somethingGeneric("Hello, World!") // Hello, World!
somethingGeneric(nil) // *nothing printed*
somethingGeneric(nil as String?) // *nothing printed*
somethingGeneric(str) // Hello, playground
str = nil
somethingGeneric(str) // *nothing printed*
somethingGeneric(list) // ["Hello", "Coder256"]
list = nil
somethingGeneric(list) // *nothing printed*
答案 5 :(得分:0)
这是我想出的在Swift 5上编译的解决方案,因为这里的许多解决方案都不是我编译的。当我使用存储的变量来帮助解决问题时,它可能被认为是hacky。我无法提供Swift 5版本的nil参数来解析为T
的类型。
class MyClass {
func somethingGeneric<T>(input: T?) {
if let input = input {
print(input)
}
}
func somethingGeneric() {
somethingGeneric(Object.Nil)
}
}
final class Object {
static var Nil: Object? //this should never be set
}