// this declaration / definition of variable is OK, as expected
var i = Optional<Int>.None
var j:Int?
// for the next line of code compiler produce a nice warning
// Variable 'v1' inferred to have type 'Optional<Void>' (aka 'Optional<()>'), which may be unexpected
var v1 = Optional<Void>.None
// but the next sentence doesn't produce any warning
var v2:Void?
// nonoptional version produce the warning 'the same way'
// Variable 'v3' inferred to have type '()', which may be unexpected
var v3 = Void()
// but the compiler feels fine with the next
var v4: Void = Void()
有什么区别?为什么Swift编译器总是很开心,如果类型不是&#39; Void&#39; ?
答案 0 :(得分:2)
警告中的关键词是“推断”。斯威夫特不喜欢推断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()
这是合法的Swift,但它会生成“推断为具有类型'()'”警告。这是一个非常容易犯的错误。至少如果你试图分配一些不会返回结果的结果,你会想要一个警告。
那么我们如何分配不返回结果的结果呢?这是因为每个函数都会返回一个结果。如果返回Void
,我们只允许省略该信息。重要的是要记住Void
并不意味着“没有类型”或“没有”。它只是()
的一个类型,它是零元素的元组。它与Int
一样有效。
上述代码的完整形式为:
func foo() -> () { return () }
let x = foo()
这会返回相同的警告,因为它是一样的。我们被允许删除-> ()
和return ()
,但它们存在,因此如果我们愿意,我们可以将()
分配给x
。但我们不太可能想要这样做。我们几乎肯定犯了一个错误,编译器警告我们。如果由于某种原因我们想要这种行为,那很好。这是合法的斯威夫特。我们只需要明确类型而不是依赖类型推断,警告就会消失:
let x: Void = foo()
Swift在您的示例中生成警告非常一致,您确实需要这些警告。这根本不是任意的。
编辑:您添加了不同的示例:
var v = Optional<Void>()
这会生成错误:ambiguous use of 'init()'
。这是因为编译器不确定您的Optional.init()
是.None
还是Optional.init(_ some: ())
,而.Some(())
是1
。禁止使用不明确的类型,因此会出现严重错误。
在Swift中,任何值都将隐含地转换为等效的1元组。例如,(1)
和Int
是不同的类型。第一个是Int
,第二个是包含foo()
的元组。但是Swift会默默地为你转换这些(这就是为什么你有时看到括号在错误信息中出现在令人惊讶的地方)。所以foo(())
和()
是一回事。在几乎所有可能的情况下,这都无关紧要。但是在这种情况下,类型确实是var i = Optional<Int>()
,这很重要并且使事情变得模棱两可。
Optional.init()
这明确指出nil
并返回{{1}}。
答案 1 :(得分:0)
编译器警告您“虚拟”类型Void
,它实际上是空元组()
的别名,并且没有太多用法。
如果你没有明确指出你希望你的变量是Void
类型,并让编译器推断出类型,它会警告你这个,因为它可能是你不想要的首先要这样做。
例如:
func doSomething() -> Void {
}
let a = doSomething()
无论如何,会给你一个警告,只有一个可能的值doSomething()
可以返回 - 一个空元组。
另一方面,
let a: Void = doSomething()
当您明确告诉编译器您需要Void
变量时,不会生成警告。