我喜欢这样一个事实:Go并没有给我百万种方法来做简单的事情 - 借用Python的禅宗,“应该有一个 - 最好只有一个 - 显而易见的方法。”
但是,我不清楚实例化类型的首选/惯用方法。基本类型很简单:
n := 0
t := 1.5
str := "Hello"
但是结构呢?以下是等效的,如果是,哪个是首选的,为什么?
var f Foo
f := Foo{}
切片怎么样?我可以 var xs []int
, xs := []int{}
, 要么 xs := make([]int)
,但我认为第一种选择(与结构相对)与其他选项不同?我认为这也适用于地图。
有了指针,我听到了 new
应该避免。这是一个很好的建议,如果是这样,那将被视为有效的用法 new
?
我意识到这可能部分是一种风格问题,但是在任何情况下,选择特定风格的理由都会有所帮助。
声明变量时,在哪里 T
是某种类型:
var name T
Go为您提供了一段未初始化的“归零”内存。
对于原语,这意味着 var name int
将是0,和 var name string
将会 ””。在 C吧 威力 被归零,或者可能出乎意料。 Go保证未初始化的变量是类型的零等价物。
内部切片,贴图和通道被视为指针。指针零值为零,表示它指向零内存。如果不尝试初始化,如果尝试对其进行操作,可能会遇到恐慌。
该 make
功能专门用于切片,地图或通道。 make函数的参数是:
make(T type, length int[, capacity int]) // For slices.
make(T[, capacity int]) // For a map.
make(T[, bufferSize int]) // For a channel. How many items can you take without blocking?
切片 length
是它开始的项目数量。容量是在需要调整大小之前分配的内存(内部,新大小* 2,然后复制)。有关更多信息,请参阅 有效围棋:使用make分配。
结构: new(T)
相当于 &T{}
不是 T{}
。 *new(T)
相当于 *&T{}
。
切片: make([]T,0)
相当于 []T{}
。
地图: make(map[T]T)
相当于 map[T]T{}
。
至于哪种方法更受欢迎,我问自己以下问题:
我现在知道函数内的值吗?
如果答案是“是”,那么我选择以上其中一个 T{...}
。如果答案是“否”,那么我使用make或new。
例如,我会避免这样的事情:
type Name struct {
FirstName string
LastName string
}
func main() {
name := &Name{FirstName:"John"}
// other code...
name.LastName = "Doe"
}
相反,我会做这样的事情:
func main() {
name := new(Name)
name.FirstName = "John"
// other code...
name.LastName = "Doe"
}
为什么?因为通过使用 new(Name)
我明确表示我 打算 以后填写值。如果我用过 &Name{...}
我不打算在以后在同一函数中添加/更改值而不读取其余代码。
不需要指针时,结构例外。我会用的 T{}
,但如果我打算添加/更改值,我不会在其中添加任何内容。当然 *new(T)
也有效,但这就像使用 *&T{}
。 T{}
在这种情况下是更干净,虽然我倾向于使用带结构的指针,以避免在传递它时复制。
要记住的另一件事是,a []*struct
比调整大小更小,更便宜 []struct
,假设struct比指针大得多,通常是4-8个字节(64位上8个字节?)。
您可以查看Go标准库源代码,您可以在其中找到许多惯用的Go代码。
你是对的: var xs []int
与其他两个变体不同,因为它不“初始化”xs,xs为零。而其他两个真正构成一个切片。 xs := []int{}
如果您需要一个零上限的空切片,这是很常见的 make
为您提供更多选择:长度和容量。另一方面,通常以nil切片开始并通过附加填充来填充 var s []int; for ... { s = append(s, num) }
。
new
不能总避免,因为它是创建指针的唯一方法,例如到uint32或其他内置类型。但你是对的,写作 a := new(A)
是非常罕见的,主要是作为 a := &A{}
因为这可以变成 a := &A{n: 17, whatever: "foo"}
。用法 new
并不是真的气馁,但考虑到结构文字的能力,它看起来就像从Java到我的遗留物。
在与Google IO的Go团队进行炉边聊天期间,观众中的某个人向Go团队询问了他们希望从该语言中获取的内容。
Rob说,他希望声明变量的方式更少,并提到:
冒号等于覆盖,命名结果参数( https://plus.google.com/+AndrewGerrand/posts/LmnDfgehorU),在for循环中重用的变量令人困惑,特别是对于闭包。然而,语言可能不会有太大变化。
声明变量时,在哪里 T
是某种类型:
var name T
Go为您提供了一段未初始化的“归零”内存。
对于原语,这意味着 var name int
将是0,和 var name string
将会 ””。在 C吧 威力 被归零,或者可能出乎意料。 Go保证未初始化的变量是类型的零等价物。
内部切片,贴图和通道被视为指针。指针零值为零,表示它指向零内存。如果不尝试初始化,如果尝试对其进行操作,可能会遇到恐慌。
该 make
功能专门用于切片,地图或通道。 make函数的参数是:
make(T type, length int[, capacity int]) // For slices.
make(T[, capacity int]) // For a map.
make(T[, bufferSize int]) // For a channel. How many items can you take without blocking?
切片 length
是它开始的项目数量。容量是在需要调整大小之前分配的内存(内部,新大小* 2,然后复制)。有关更多信息,请参阅 有效围棋:使用make分配。
结构: new(T)
相当于 &T{}
不是 T{}
。 *new(T)
相当于 *&T{}
。
切片: make([]T,0)
相当于 []T{}
。
地图: make(map[T]T)
相当于 map[T]T{}
。
至于哪种方法更受欢迎,我问自己以下问题:
我现在知道函数内的值吗?
如果答案是“是”,那么我选择以上其中一个 T{...}
。如果答案是“否”,那么我使用make或new。
例如,我会避免这样的事情:
type Name struct {
FirstName string
LastName string
}
func main() {
name := &Name{FirstName:"John"}
// other code...
name.LastName = "Doe"
}
相反,我会做这样的事情:
func main() {
name := new(Name)
name.FirstName = "John"
// other code...
name.LastName = "Doe"
}
为什么?因为通过使用 new(Name)
我明确表示我 打算 以后填写值。如果我用过 &Name{...}
我不打算在以后在同一函数中添加/更改值而不读取其余代码。
不需要指针时,结构例外。我会用的 T{}
,但如果我打算添加/更改值,我不会在其中添加任何内容。当然 *new(T)
也有效,但这就像使用 *&T{}
。 T{}
在这种情况下是更干净,虽然我倾向于使用带结构的指针,以避免在传递它时复制。
要记住的另一件事是,a []*struct
比调整大小更小,更便宜 []struct
,假设struct比指针大得多,通常是4-8个字节(64位上8个字节?)。
您可以查看Go标准库源代码,您可以在其中找到许多惯用的Go代码。
你是对的: var xs []int
与其他两个变体不同,因为它不“初始化”xs,xs为零。而其他两个真正构成一个切片。 xs := []int{}
如果您需要一个零上限的空切片,这是很常见的 make
为您提供更多选择:长度和容量。另一方面,通常以nil切片开始并通过附加填充来填充 var s []int; for ... { s = append(s, num) }
。
new
不能总避免,因为它是创建指针的唯一方法,例如到uint32或其他内置类型。但你是对的,写作 a := new(A)
是非常罕见的,主要是作为 a := &A{}
因为这可以变成 a := &A{n: 17, whatever: "foo"}
。用法 new
并不是真的气馁,但考虑到结构文字的能力,它看起来就像从Java到我的遗留物。
在与Google IO的Go团队进行炉边聊天期间,观众中的某个人向Go团队询问了他们希望从该语言中获取的内容。
Rob说,他希望声明变量的方式更少,并提到:
冒号等于覆盖,命名结果参数( https://plus.google.com/+AndrewGerrand/posts/LmnDfgehorU),在for循环中重用的变量令人困惑,特别是对于闭包。然而,语言可能不会有太大变化。