Golang语法问题:接口数组的使用疑问

Golang语法问题:接口数组的使用疑问 在我编写的程序中,我需要向GTK Treeview添加一个新行,代码如下:

// 将视频添加到列表
iter := listStore.Append()
err := listStore.Set(iter, []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
	[]interface{}{thumbnail,
		video.SubscriptionName,
		video.Added.Format(constDateLayout),
		video.Title,
		progress,
		backgroundColor,
		video.ID,
		duration,
		progressText,
		foregroundColor})

这段代码运行正常,但我很好奇为什么最后一个数组([]interface{}{…})中多了一组花括号?如果你将其与第二个参数([]int{…})进行比较,后者只有一组花括号。显然,我只是找到了一段能工作的代码并复制粘贴了它。但现在我很好奇它为什么能工作……

【编辑】加粗(使用**)似乎不起作用……?


更多关于Golang语法问题:接口数组的使用疑问的实战教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

[]int{0, 1, 2} 表示一个 int 类型的切片 ([]),并用 {0, 1, 2} 初始化它。

[]interface{}{0, 1, 2} 表示一个 interface{} 类型的切片,并用 {0, 1, 2} 初始化它。

Go 语言支持匿名类型。你也可以这样写:

stringers := []interface { String() string }{
    new(bytes.Buffer),
    big.NewFloat(123.456),
}

更多关于Golang语法问题:接口数组的使用疑问的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


[]int{0, 1, 2} 表示一个 int 类型的切片([]),并用 {0, 1, 2} 初始化它。

[]interface{}{0, 1, 2} 表示一个 interface{} 类型的切片,并用 {0, 1, 2} 初始化它。

这部分我理解了…

Go 可以有匿名类型。你也可以这样写:

stringers := []interface { String() string }{
    new(bytes.Buffer),
    big.NewFloat(123.456),
}

这个我不完全理解,花括号是只适用于接口的东西吗?我的意思是,你不能写 int{}{0,1,2,3},对吧?

我想你能看出来,我是 Go 的新手,而且我还没有真正研究过接口…[编辑] 我可能应该去研究一下!

很多人觉得 interface{} 是 Go 中的一个特殊类型,但实际上它和上面变量 y 的类型定义是同一个东西,只是 interface{} 在其 {} 之间没有列出任何方法,所以它被明确地称为 “空接口”

啊,是的,空接口,这个我确实记得读到过。那么基本上可以说,一个 interface{} 几乎可以是任何东西,有点像 C# 中的 Object,是吗?当然,在我这个特定的 GTK 树视图案例中,GTK 的开发者不想限制用户能在树视图中放入什么内容,所以他们要求:告诉我们你有多少列(int),以及你希望每列包含什么(interface{})。最后这个参数可以是任何东西,具有任何方法签名……?

既然你可以向树视图中添加图像、文本、进度条等等,我想你基本上无法对能放入其中的内容做任何限定。

附言:感谢你详尽且信息量丰富的回答……这对我来说真的是一个“啊哈”时刻 🙂

是的。我的观点是,大括号的存在是因为 []interface{} 表示“一个实现了空接口的元素的切片”。类似地,[]interface{ String() string } 表示“一个拥有返回 stringString() 方法的元素的切片”。

你可以使用类型字面量(例如 interface{}interface{ String() string }struct{ S string, I int} 等),也可以定义你自己的类型,使其拥有一个名称:

type Anything interface {
	// No methods needed to implement this interface.
	// It is the empty interface.
}

type Stringer interface {
	String() string
}

type MyStruct struct {
	S string
	I int
}

然后你就可以直接使用这些名称:

values := []Anything{
	thumbnail,
	video.SubscriptionName,
	video.Added.Format(constDateLayout),
	video.Title,
	progress,
	backgroundColor,
	video.ID,
	duration,
	progressText,
	foregroundColor,
}

在Go语言中,[]interface{}{...} 的语法是正确的,它创建了一个 interface{} 类型的切片(即空接口切片)。这里有两层花括号的原因如下:

  1. 第一层花括号 []interface{}:这是类型声明,表示一个空接口切片。
  2. 第二层花括号 {...}:这是复合字面量(composite literal),用于初始化切片中的元素。

相比之下,[]int{...} 只有一层花括号,因为它将类型声明和初始化合并了。实际上,[]interface{}{...} 也可以写成 []interface{}{...}(中间没有空格),但为了清晰,通常会在类型和初始化值之间加空格。

示例代码:

package main

import "fmt"

func main() {
    // 示例1: int切片初始化
    intSlice := []int{1, 2, 3}
    fmt.Println(intSlice) // 输出: [1 2 3]

    // 示例2: interface{}切片初始化
    ifaceSlice := []interface{}{"字符串", 42, true, 3.14}
    fmt.Println(ifaceSlice) // 输出: [字符串 42 true 3.14]

    // 示例3: 多行初始化(更清晰)
    treeViewData := []interface{}{
        thumbnail,
        video.SubscriptionName,
        video.Added.Format(constDateLayout),
        video.Title,
        progress,
        backgroundColor,
        video.ID,
        duration,
        progressText,
        foregroundColor,
    }
    // 使用treeViewData...
}

在你的GTK代码中:

// 两种写法等价:
// 1. 紧凑写法
[]interface{}{value1, value2, value3}

// 2. 标准写法
[]interface{}{
    value1,
    value2,
    value3,
}

关键点:

  • interface{} 是Go中的空接口类型,可以容纳任何类型的值
  • 当类型本身包含花括号(如 []interface{})时,初始化需要额外的花括号
  • 这与 map[string]int{"a": 1} 的语法类似,类型声明中已经包含花括号

这种语法设计确保了类型声明的完整性,同时允许清晰的复合字面量初始化。

回到顶部