元组与元组

tuple versus Tuple

为什么在使用 tupleTuple 转换向量时会得到以下不同的结果?

julia> a = [1, 2, 3]
3-element Vector{Int64}:
1
2
3

julia> tuple(a)
([1, 2, 3],)

julia> Tuple(a)
(1, 2, 3)

广播给出了相同的结果:

julia> tuple.(a)
3-element Vector{Tuple{Int64}}:
(1,)
(2,)
(3,)

julia> Tuple.(a)
3-element Vector{Tuple{Int64}}:
(1,)
(2,)
(3,)

(后者并不奇怪,因为它只是将单个数字转换为元组。)

(这是 Julia 1.6.1。)

Tuple 是一种类型,与 Julia 基础中的所有集合一样,如果您将另一个集合传递给它,它会根据另一个集合的内容创建该类型的实例。所以 Tuple([1, 2, 3]) 构造一个值 1、2 和 3 的元组,就像 Set([1, 2, 3]) 构造一组相同的值一样。同样,如果你写 Dict([:a => 1, :b => 2, :c => 3]),你会得到一个包含 :a => 1:b => 2:c => 3 对的字典。当构造函数的参数是迭代器时,这也能很好地工作;一些例子:

julia> Tuple(k^2 for k=1:3)
(1, 4, 9)

julia> Set(k^2 for k=1:3)
Set{Int64} with 3 elements:
  4
  9
  1

julia> Dict(string(k, base=2, pad=2) => k^2 for k=1:3)
Dict{String, Int64} with 3 entries:
  "10" => 4
  "11" => 9
  "01" => 1

所以这就是 Tuple 以这种方式工作的原因。另一方面,tuple 函数是一个从其参数生成元组的函数,如下所示:

julia> tuple()
()

julia> tuple(1)
(1,)

julia> tuple(1, "two")
(1, "two")

julia> tuple(1, "two", 3.0)
(1, "two", 3.0)

为什么要有 tuple 而不是只有 Tuple?您可以将最后一个示例表示为 Tuple([1, "two", 3.0])。然而,这需要构造一个临时的无类型数组来迭代它并从它的内容中生成一个元组,这是非常低效的。要是有一种更高效的容器类型就好了,编译器通常可以消除...的构造……就像一个元组。为此,我们会写 Tuple((1, "two", 3.0))。哪个有效,但是完全多余,因为 (1, "two", 3.0) 已经是您想要的元组。那么为什么要使用 tuple?大多数时候你不需要,你只是使用 (1, "two", 3.0) 语法来构造一个元组。但有时您需要一个实际的函数,您可以将其应用于某些值以获得它们的元组——tuple 就是那个函数。你实际上可以创建一个匿名函数来很容易地做到这一点:(args...) -> (args...,)。您可以将 tuple 视为该函数的便捷缩写。