警告中的关键词是“推断”。斯威夫特不喜欢推断Void
,因为它通常不是你的意思。但是,如果你明确地要求它(: Void
)那么这很好,以及如果这是你的意思,你将如何平息警告。
重要的是要识别哪些类型是推断的,哪些是显式的。推断是“从证据和推理中推断或推断(信息),而不是从明确的陈述中推断出来”。它不是“猜测”或“选择”的同义词。如果类型不明确,那么编译器会产生一个错误。该类型必须是总是是明确的。问题是,是否明确定义,或通过推断基于明确的信息定义。
此语句具有类型推断:
let x = Foo()
类型的Foo()
明确已知,但x
的类型是基于整个表达式(Foo
)的类型推断。它有明确的定义和完全明确的,但它是推断。
这种说法没有类型推断:
let x: Foo = Foo()
而且,这里还有没有类型推论:
var x: Foo? = nil
x = Foo()
在第二行的类型x
(Foo?
)是明确的,因为它在上面的行中被明确定义。
这就是为什么有些示例会生成警告(当存在Void
推断时),而另一些则不会(仅当明确使用Void
时)。为什么我们关心推断Void
?因为它可能非常容易发生,并且几乎没有用处。例如:
func foo() {}
let x = foo()
这是合法的斯威夫特,但它生成一个“推断为有型‘()’”的警告。这是一个非常容易的错误。至少如果您尝试分配不返回结果的结果,则至少需要警告。
那么我们如何分配不返回结果的结果呢?这是因为每个函数都返回一个结果。如果退货是Void
,我们只允许忽略这些信息。请务必记住Void
并不意味着“无类型”或“无”。它只是()
的一个typealias,它是零元素的元组。它与Int
一样有效。
上述代码的完整形式是:
func foo() ->() { return() }
let x = foo()
这将返回相同的警告,因为它是一回事。我们可以放弃->()
和return()
,但它们存在,因此如果我们愿意,我们可以将()
指定为x
。但是我们想要的是不可能的。我们几乎肯定犯了一个错误,编译器就此警告我们。如果由于某种原因我们想要这种行为,那很好。这是合法的Swift。我们只需要更明确一些类型,而不是依赖于类型推断,并警告将消失:
let x: Void = foo()
斯威夫特是在您的实例的产生警告非常一致,而且你真的希望这些警告。它根本不是任意的。
编辑:您加入不同示例:
var v = Optional<Void>()
这将生成错误:ambiguous use of 'init()'
。这是因为编译器不确定您的意思是Optional.init()
将是.None
还是Optional.init(_ some:())
,这将是.Some(())
。不明确的类型被禁止,所以你会得到一个硬性错误。
在Swift中,任何值都会隐式转换为等价的1元组。例如,1
和(1)
是不同的类型。第一个是Int
,第二个是包含Int
的元组。但Swift会默默地为你转换这些(这就是为什么你有时会在错误信息中令人惊讶的地方看到括号出现)。所以foo()
和foo(())
是一样的东西。在几乎所有可能的情况下,这并不重要。但在这种情况下,类型真的是()
,这很重要,并使事情变得模糊。
var i = Optional<Int>()
这明确地指Optional.init()
并返回nil
。
'v2'只声明,试图给它分配一个值,看看如果编译器是确定与 – Cristik
@Cristic V2的右边都有默认值为零 – user3441734