Golang 结构体初识
结构体的创建以及定义
- 结构体的定义:
结构体是用户定义的类型,表示若干个字段(Field)的集合。
有时应该把数据整合在一起,而不是让这些数据没有联系。
这种情况下可以使用结构体。
- 声明命名结构体:
- 语法:type 结构体的名字 struct {字段名 类型}
- 命名结构体意味定义了一个新的类型的数据结构;
- 可以创建该类型的数据;
- 创建命名结构体:
- 创建命名结构体时,结构体中的字段名的顺序不需要与声明中的结构体中的字段顺序一致;
- 创建命名结构体时, 省略了字段名的时候,就必须和声明结构体的时候的字段的顺序一致;
- 示例:
package main import ( "fmt" ) type Employee struct { firstName, lastName string age, salary int } func main() { // 创建Employee类型的结构体,不省略字段名 emp1 := Employee{ firstName: "Sam", age: 25, salary: 500, lastName: "Anderson", } //创建Employee类型的结构体,省略字段名 emp2 := Employee{"Thomas", "Paul", 29, 800} fmt.Println("Employee 1", emp1) fmt.Println("Employee 2", emp2) }
- 声明匿名结构体:
- 语法:var 变量名 struct {字段名 类型}
- 创建匿名结构体:
- 匿名结构体,因为没有类型,所以能且只能创建一个变量;
- 示例:
package main import ( "fmt" ) func main() { emp3 := struct { firstName, lastName string age, salary int }{ firstName: "Andreah", lastName: "Nikola", age: 31, salary: 5000, } fmt.Println("Employee 3", emp3) }
- 结构体中的零值:
- 定义结构体后, 初始化不给任何字段赋值, 则该结构体会打印出 每个字段所对应的零值;
- 注意若不需要给某些字段赋值,请用该类型的零值代替,初始化时,缺少字段,会报错;
- 示例:
package main import ( "fmt" ) type Employee struct { firstName, lastName string age, salary int } func main() { var emp4 Employee //zero valued structure fmt.Println("Employee 4", emp4) } // 打印内容: Employee 4 { 0 0}
结构体中的字段
- 访问结构体中的字段:
- 点号操作符用于访问结构体中的字段;
- 在访问结构体的时候亦可对字段进行重新赋值:
- 示例:
package main import ( "fmt" ) func main() { type MyTestStruct struct { name string age int } test_struct := MyTestStruct{"fusheng", 38} fmt.Println(test_struct) test_struct.name = "liangnian" fmt.Println(test_struct) } // 打印内容: {fusheng 38} {liangnian 38}
- 结构体的指针:
- 声明一个指向自定义的结构体的指针;
- 解引用该指针访问字段;允许省略 * 号
- 示例:
package main import ( "fmt" ) type MyTestStruct struct { name string age int } func main() { test_struct := &MyTestStruct{"fusheng", 38} fmt.Println(test_struct)
// 正常解引用访问字段 fmt.Println((*test_struct).name)
// 省略*() 访问字段 fmt.Println(test_struct.name) }
- 匿名字段:
- 字段可以只有类型,而没有字段名;
- 匿名字段虽说可以没有字段名,但是实际上,他们的类型就是他们的字段名;
- 示例:
package main import ( "fmt" ) type MyTestStruct struct { string int } func main() { test_struct := MyTestStruct{ "fusheng", 18, // 注意 在最后需用, 或} 用来结尾 } fmt.Println(test_struct) // 匿名字段赋值 test_struct_2 := MyTestStruct{} test_struct_2.string = "liangnina" test_struct_2.int = 17 fmt.Println(test_struct_2) }
结构体的嵌套
- 定义:
- 在结构体中的,设置一个类型为其他结构体的字段。 这样的结构体称为嵌套结构体。
- 示例:
package main import ( "fmt" ) type AgeStruct struct { old_time, new_time int } type MyTestStruct struct { string int AgeStruct } func main() { var age AgeStruct age.old_time = 0 age.new_time = 10 test_struct := MyTestStruct{ "fusheng", 18, age, } fmt.Println(test_struct) }
- 提升字段:
- 定义: 在结构体中有匿名的结构体字段,该匿名字段执行的结构体里的字段就被称为提升字段;
- 示例:
package main import ( "fmt" ) type AgeStruct struct { old_time, new_time int } type MyTestStruct struct { string int AgeStruct } func main() { var age AgeStruct age.old_time = 0 age.new_time = 10 test_struct := MyTestStruct{ "fusheng", 18, age, } fmt.Println(test_struct) // 在MyTestStruct结构体中可以通过点直接获取 // 匿名字段中AgeStruct结构体中的字段, // 将这种字段称为 提升字段 fmt.Println(test_struct.old_time) fmt.Println(test_struct.new_time) }
导出结构体
- 导出结构体:
如果结构体名称以大写字母开头,则它是其他包可以访问的导出类型(Exported Type)。
同样,如果结构体里的字段首字母大写,它也能被其他包访问到。
- 导出示例:
- 文件结构:
- 代码示例:
// main.go package main import ( "fmt" "mystruct/struct_demo" ) func main() { var a struct_demo.DemoStruct a.Name = "fusheng" // a.add = "XXXXX" 报错:a.add undefined (cannot refer to unexported field or method add) fmt.Println(a) } // demo.go package struct_demo type DemoStruct struct { Name string Age int add string }
结构体的相等性
- 结构体是 值类型
- 所有字段皆是可比较的,则该结构体也是可比较: - 两个结构体变量的对应字段相等,则这两个变量也是相等的。 - 结构体包含不可比较的字段,则结构体变量也不可比较
- 代码示例:
- 可比较的结构体示例:
package main import ( "fmt" ) type name struct { firstName string lastName string } func main() { name1 := name{"Steve", "Jobs"} name2 := name{"Steve", "Jobs"} if name1 == name2 { fmt.Println("name1 and name2 are equal") } else { fmt.Println("name1 and name2 are not equal") } name3 := name{firstName:"Steve", lastName:"Jobs"} name4 := name{} name4.firstName = "Steve" if name3 == name4 { fmt.Println("name3 and name4 are equal") } else { fmt.Println("name3 and name4 are not equal") } } // 打印结果: name1 and name2 are equal name3 and name4 are not equal
- 不可比较的示例代码:
package main import ( "fmt" ) type image struct { data map[int]int } func main() { image1 := image{data: map[int]int{ 0: 155, }} image2 := image{data: map[int]int{ 0: 155, }} if image1 == image2 { fmt.Println("image1 and image2 are equal") } } // 因为是不可比较的所以会报错: // 报错信息:invalid operation: image1 == image2 (struct containing map[int]int cannot be compared)