是否有任何可能显式使用空元组 () 的实例(值),即 typealias 'Void' 的实例?

Are there any possible explicit uses of instances (values) of empty tuples (), i.e., of instances of typealias 'Void'?

问题:

我知道这些空元组在标准意义上可以用来定义void函数。当我错误地定义了一个带有空元组 value var a = ()() 类型)的变量时,我开始怀疑这些空元组值是否可以在某些上下文中使用.有人知道这样的应用程序吗?


示例:数组和可选值的可能应用?

例如,我们可以创建一个可选的空元组数组,它​​自然只能容纳 nil()

/* Optionals */
var foo: ()? = ()
print(foo.dynamicType) // Optional<()>

var arr : [()?] = [foo]
for i in 2...8 {
    if i%2 == 0 {
        arr.append(nil)
    }
    else {
        arr.append(foo)
    }
}
print(arr) // [Optional(()), nil, Optional(()), ... ]

由于空元组的内存占用很小,对于 micro-memory-management 对于 "boolean nil/not nil" 这似乎很整洁,但是由于类型 Bool 具有相同的小内存占用,我不能真的在这里看到任何直接使用,即使在我们确实需要 bit-low 优化我们的操作的(不同)场景中也是如此。


也许我只是在用一些狭窄的无法使用的应用程序追逐自己的尾巴,但无论如何:这些无效 () 存在是否有任何可能的明确用途(如 instances, 不是类型)?

假设您有两个重载相同名称的函数:

func foo()
func foo() -> Int

第一个没有 return 任何东西,第二个 return 有某种价值。在大多数情况下,尝试调用其中任何一个都会导致编译器出现歧义错误。

foo()
let a = foo()

您认为编译器会知道第一个调用明确引用第一个函数,因为它假定没有 return 值。但实际上,没有声明return类型的函数的return类型是Void,或者()。所以第一次调用其实更像这样:

let _ = foo()

并且缺少对丢弃的左值的类型注释,编译器无法推断要调用哪个 foo。您可以使用显式类型注释来消除歧义:

let b: Void = foo()
let c: Int = foo() 

好吧,这不是 Void 的一个非常好的或常见的用例,因为您一开始就倾向于避免进入这种情况。但是你要求 a use... 它是将 () 用作值而不仅仅是类型,因为你可以从 b 中检索它分配后(对你有好处)。

请注意,当你深入观察Void时,Void也在观察你。或类似的东西。

有很多地方 () 在解决 "CS" 问题时很有用,这些问题的形式通常是 "implement X using Y even though you really already have X." 例如,我可能会说,实现 Set使用词典。嗯,字典是 Key/Value 对。 Value 的类型应该是什么?实际上,我已经在有字典但没有集合的语言中看到过这种情况,人们经常使用 1 或 true 作为值。但这不是你的意思。这打开了歧义。如果该值是假的怎么办?它在集合中还是不在集合中?根据 Dictionary 实现 Set 的正确方法是 [Key: ()],然后你会得到如下代码行:

set[key] = ()

还有其他等效版本,例如您的 Optional<()>。我还可以将整数实现为 [()]Set<()>。这有点傻,但我以前做过类似的事情来探索数论。

也就是说,这些几乎都是故意不切实际的解决方案。实用的怎么样?这些通常出现在泛型编程中。例如,想象一个具有这种形式的函数:

func doThingAndReturn<T>(retval: T, f: () -> Void) -> T {
    f()
    return retval
}

这并不像听起来那么愚蠢。沿着这些思路的东西很容易出现在命令模式中。但是,如果没有 retval 怎么办?我不关心 return?好吧,没关系,只需传递一个 () 值即可。

func doThing(f: () -> Void) {
    doThingAndReturn((), f: f)
}

同样,您可能需要一个像 zipMap:

这样的函数
func zipMap<T, U>(funcs: [(T) -> U], vals: [T]) -> [U] {
    return zip(funcs, vals).map { [=13=]() }
}

这将应用一系列函数,这些函数采用 T 到类型 T 的值。即使 T 碰巧 (),我们也可以使用它,但我们必须生成一堆 () 值才能使其工作。例如:

func gen<T>(funcs: [() -> T]) -> [T] {
    return zipMap(funcs, vals: Array(count: funcs.count, repeatedValue: ()))
}

我不认为这会在 Swift 中经常出现,因为 Swift 主要是一种命令式语言,几乎在所有情况下都隐藏了它的 Void。但是当 Scala 等函数式语言过渡到命令式编程时,您确实会看到类似的事情出现。