在函数内部定义struct
与在外部定义它是否有任何影响(GC流失,性能或其他方面)?例如:
type Outside struct {
Foo string `json:"foo"`
}
func SomeFunc(b []byte) error {
outside := Outside{}
if err := json.NewDecoder(b).Decode(&outside); err != nil {
return err
}
...
}
VS
func SomeFunc(b []byte) error {
type inside struct {
Foo string `json:"foo"`
}
if err := json.NewDecoder(b).Decode(&inside); err != nil {
return err
}
...
}
是否会出现一种优先于另一种情况的情况?
答案 0 :(得分:6)
对我来说,在函数中定义的类型的主要缺点是无法在该类型上定义方法。
请参见以下示例https://play.golang.org/p/cgH01cRwDv6:
package main
import (
"fmt"
)
func main() {
type MyType struct {
Name string
}
// You cannot define a method on your type
// defined in a function, can you?
func (m MyType) String() string {
return m.Name
}
m := MyType{Name: "Hello, World!"}
fmt.Println(m)
}
以上示例将失败,并显示错误prog.go:15:27: expected ';', found 'IDENT' string (and 1 more errors)
。
答案 1 :(得分:5)
没有性能差异 - 它只是范围的差异(即,可以看到类型定义的位置)。如果你只需要一个函数中的类型,可以在那里定义它。
正如其他人所指出的那样,如果您在包级别(即函数外部)定义一个名称以大写字母开头的类型,它将被导出(即在包外可见)。如果名称不以大写字母开头,则只会在包中显示。
答案 2 :(得分:3)
我的理解是区别在于可访问性。以大写字母开头定义的结构将是可导出的,这意味着可以从其他包访问它。以小写字母开头定义的结构可以从同一个包中的任何内容访问,但不能从外部访问。在函数中定义的结构只能由该函数访问/初始化。
答案 3 :(得分:1)
正如其他人所提到的,它完全是关于限制变量范围的。如果要在函数内使用结构体,也可以使用匿名结构体。
package main
import (
"fmt"
)
func main() {
m := struct {
greeting string
name string
}{
greeting: "hello",
name: "world",
}
fmt.Printf("%v %v\n", m.greeting, m.name)
}
如果您只想在函数内部使用结构体,您可以定义结构体的字段并立即为其赋值。
答案 4 :(得分:0)
对我来说,我曾经在函数内部定义了一个结构,用于将json [] byte编组到该结构实例中并从该实例中提取一条消息。
显然,不需要定义该结构。我可以通过将json字节数组编组到interface {}中来提取消息,然后递归进行强制转换以获取所需的消息。
通过定义结构,提取消息变得非常容易:)
var errDetail struct {
Message string `json:"message"`
Success bool `json:"success"`
}
json.Unmarshal(*bytes, &errDetail)
if errDetail.Message == "" {
fmt.Println("error message is not present")
return nil
}
return errDetail.Message
答案 5 :(得分:0)
对于Konrad Kleine的问题,您仍然可以通过以下解决方法来解决 https://play.golang.org/p/50yv66LUNRt
package main
import (
"fmt"
)
func main() {
type MyType struct {
Name string
String func() string
}
InitMyType := func(m *MyType) {
m.String = func() string {
return m.Name
}
return
}
m := MyType{Name: "Hello, World!"}
initMyType(&m)
fmt.Println(m.String())
}
我同意区别只是可访问性。
但这仍然非常有用,特别是您想要的只是一个临时结构,或者当您进行单元测试时,有很多类似的结构,例如args,包中的测试用例,您无需费心为它们命名一一。
答案 6 :(得分:0)
范围不同,您可以在此处查看 Golang 规范:enter link description here
最相关的部分是:
<块引用>Go 的词法范围使用块:
表示在顶层(任何函数之外)声明的常量、类型、变量或函数(但不是方法)的标识符的范围是包块。
在函数内声明的类型标识符的范围从 TypeSpec 中的标识符开始,到最里面的包含块的末尾结束。
如果你使用go tool compile -S -N hello.go
来检查生成的汇编代码,你可以发现包级别定义的类型名称和函数内部定义的类型名称不同。
包级别
package main
import (
"fmt"
)
type Point struct {
X, Y int
}
func main() {
fmt.Printf("%v\n", Point{X: 1, Y: 2})
}
然后尝试编译并找到这一行:type."".Point SRODATA size=144
。
内部函数
package main
import (
"fmt"
)
func main() {
type Point struct {
X, Y int
}
fmt.Printf("%v\n", Point{X: 1, Y: 2})
}
然后尝试找到这一行:type.*"".Point·1 SRODATA size=56
也就是说,它们只是在编译后得到了不同的名称。