main.go
// Go语言·面向对象编程·结构体字段
package main
// 包的本质是创建不同的文件夹
// go的每一个文件都是属于一个包的
// go以包的形式管理项目和文件目录。
// import "包的路径"
import (
utils "day19/model/utils"
_"fmt"
)
var content string = `
————————————————Go语言·面向对象编程·结构体字段————————————————————
一、结构体字段
`
func main() {
utils.Entry()
}
utils.go
// Go语言·面向对象编程·结构体字段
package utils
import (
"fmt"
"encoding/json"
)
var layout string = "2006-01-02"
// 全局变量
var Author string = "Jhou Shuai"
// 全局变量
var Description string = "Go语言·面向对象编程·结构体字段"
//全局变量:使用反引号来定义多行字符串
var Content string = `
————————————————Go语言·面向对象编程·结构体字段————————————————————
一、结构体 struct
值类型
自定义的数据类型
type 结构体名称 struct {
Field1 type
Field2 type
}
结构体字段=属性=field
字段类型:基本数据类型,数组,或引用类型(切片,map)
结构体(类)
结构体变量(实例)
1.将一类事物的特征提取出来,形成一个新的数据类型,就是一个结构体。
2.通过这个结构体,我们可以创建多个变量(实例、对象)
3.声明、创建一个结构体时,已分配空间。如果没有赋值,则默认为空值(或零值)
结构体字段数据类型 默认值
bool类型 false
数值 0
字符串 ""
****指针,slice,map的零值都是nil ,即还没有分配空间,
****温馨提示:使用的时候,需要先make
4.不同的结构体变量的字段是独立,互不影响,一个结构体变量字段的改变,不影响另
外一个,结构体是值类型。
二、注意事项和使用细节
1.结构体的所有字段在内存中是连续的
int 8个字节,string 16个字节
// cat的地址: 0xc000020140 = &cat.Name
// cat.Name 的地址: 0xc000020140
// cat.Age 的地址: 0xc000020150 0xc000020150 = 0xc000020140 + 16
// cat.Color的地址: 0xc000020158 0xc000020158 = 0xc000020150 + 8
// cat.Hobby的地址: 0xc000020168 0xc000020168 = 0xc000020158 + 16
2.结构体是用户单独定义的类型,和其他类型进行转换时需要有完全相同的字段(名字、个数、类
型)
type A struct {
Num int
}
type B struct {
Num int
}
var a A
var b B
a = A(b)
3.结构体进行type重新定义(相当于取别名),Go语言认为是新的数据类型,但是相互间可以强
制转换转
type Student struct {
Name string
Age int
}
type Stu Student
var stu1 Student
var stu2 Stu
// 强制转换
stu2 = Stu(stu1)
type integer int
var i integer = 10
var j int = 20
// 强制转换
j = int(i)
4.struct的每个字段上,可以写一个tag标签,tag可以通过反射机制获取
序列化[json格式],反序列化
type Monster struct {
Name string tag标签
Age int tag标签
Skill string tag标签
}
// 详见如下函数:
jsonStruct()
`
type Cat struct {
Name string
Age int
Color string
Hobby string
}
type Person struct {
Name string
Age int
Scores [5]float64 //数组
ptr *int //指针 new
slice []int //切片 make
myp map[string]string //map make
}
type Monster struct {
Name string `json:"name"` //tag标签
Age int `json:"age"` //tag标签
Skill string `json:"skill"` //tag标签
}
type Point struct {
x int
y int
}
type Rect struct {
left,right Point
}
type Rect2 struct {
left,right *Point
}
/**
* [Init 入口]
* @author Jhou Shuai
* @datetime 2019-05-18T11:58:33+0800
*/
func Entry() {
jsonStruct()
}
func structInit() {
// 1.结构体Cat和结构体变量cat
// 2.类Cat和实例(对象)cat
// 3.结构体是值类型
var cat Cat
cat.Name = "小喵喵"
cat.Age = 3
cat.Color="白色"
cat.Hobby="吃<。)#)))≦"
fmt.Println(cat)
fmt.Println()
fmt.Printf("cat的地址: %p \n\n",&cat)
fmt.Printf("cat.Name 的地址: %p \n",&cat.Name)
fmt.Printf("cat.Age 的地址: %p \n",&cat.Age)
fmt.Printf("cat.Color的地址: %p \n",&cat.Color)
fmt.Printf("cat.Hobby的地址: %p \n",&cat.Hobby)
// cat的地址: 0xc0000660c0 == &cat.Name 的地址
// cat.Name 的地址: 0xc0000660c0
// cat.Age 的地址: 0xc0000660d0 0xc0000660d0 = 0xc0000660c0 + 16
// cat.Color的地址: 0xc0000660d8 0xc0000660d8 = 0xc0000660d0 + 8
// cat.Hobby的地址: 0xc0000660e8 0xc0000660e8 = 0xc0000660d8 + 16
}
func structUsedDetail() {
// 值类型
// ****字段数据类型:指针,slice,map的零值都是nil ,即还没有分配空间,
// ****温馨提示:使用的时候,需要先make
// 定义结构体变量
// { 0 [0 0 0 0 0] <nil> [] map[]}
var p1 Person
if p1.ptr == nil {
fmt.Println("p1.ptr[指针] is nil , 没分配空间")
}
if p1.slice == nil {
fmt.Println("p1.slice[切片] is nil , 没分配空间")
}
if p1.myp == nil {
fmt.Println("p1.myp[map] is nil , 没分配空间")
}
// 出错啦:
// panic: runtime error: invalid memory address or nil pointer dereference
// *p1.ptr = 100
// 正确使用
p1.ptr = new(int)
fmt.Println(*p1.ptr) // 0
*p1.ptr = 100
// 出错啦:
// panic: runtime error: index out of range
// p1.slice[0] = 100
// 正确使用
// 使用切片,一定要先make
p1.slice = make([]int,2)
p1.slice[0] = 100
p1.slice[1] = 110
// 出错啦:
// panic: assignment to entry in nil map
// p1.myp["No001"] = "妯娌"
// 使用map,一定要先make
p1.myp = make(map[string]string)
p1.myp["No001"] = "妯娌"
p1.myp["No002"] = "咕力咕力"
fmt.Println(p1)
fmt.Println()
// 不同的结构体变量的字段是独立,互不影响,一个结构体变量字段的改变,不影响另
// 外一个,结构体是值类型。
var m1 Monster
m1.Name = "青龙"
m1.Age = 2000
m2 := m1
m2.Name = "朱雀"
fmt.Println(m1)
fmt.Println(m2)
}
func createStructMethod() {
// 方式一:
var p1 Person
fmt.Println(p1) //{ 0 [0 0 0 0 0] <nil> [] map[]}
// 方式二:
// {周帅 18 [34 45.23 12 44 55] 0xc00006a080 [0 0] map[]}
// var p2 = Person{"周帅",18,[5]float64{34,45.23,12,44,55},new(int),make([]int,2),make(map[string]string)}
// var m Monster = Monster{}
m1 := Monster{"白虎",1000,"圣光降临"}
fmt.Println(m1) //{白虎 1000}
// 方式三:指针
var m2 *Monster = new(Monster)
// m2是指针,给字段赋值的标准方式:
(*m2).Name = "狐狸"
(*m2).Age = 998
fmt.Println(*m2) //{狐狸 998}
// 可以改写成如下(简化,但底层会自动加上取值运算*):
m2.Name = "饕餮"
m2.Age = 100000
fmt.Println(*m2) //{饕餮 100000}
// 方式四:指针 地址符&
// var m3 *Monster = &Monster{"小乌龟",10000}
var m3 *Monster = &Monster{}
// m3是指针,给字段赋值的标准方式:
(*m3).Name = "小兔子"
(*m3).Age = 3
fmt.Println(*m3) //{小兔子 3}
// 可以改写成如下(简化,但底层会自动加上取值运算*):
m3.Name = "白天鹅"
m3.Age = 2
fmt.Println(*m3) //{白天鹅 2}
}
/**
* [memoryStruct 结构体内存分配]
* @author Jhou Shuai
* @datetime 2019-06-02T10:24:47+0800
*/
func memoryStruct(){
// 1.结构体Cat和结构体变量cat
// 2.类Cat和实例(对象)cat
// 3.结构体是值类型
var cat Cat
cat.Name = "小喵喵"
cat.Age = 3
cat.Color="白色"
cat.Hobby="吃<。)#)))≦"
fmt.Println(cat)
fmt.Println()
fmt.Printf("cat的地址: %p \n\n",&cat)
fmt.Printf("cat.Name 的地址: %p \n",&cat.Name)
fmt.Printf("cat.Age 的地址: %p \n",&cat.Age)
fmt.Printf("cat.Color的地址: %p \n",&cat.Color)
fmt.Printf("cat.Hobby的地址: %p \n",&cat.Hobby)
// cat的地址: 0xc000020140 = &cat.Name
// cat.Name 的地址: 0xc000020140
// cat.Age 的地址: 0xc000020150 0xc000020150 = 0xc000020140 + 16
// cat.Color的地址: 0xc000020158 0xc000020158 = 0xc000020150 + 8
// cat.Hobby的地址: 0xc000020168 0xc000020168 = 0xc000020158 + 16
fmt.Println()
cat1 := cat
cat1.Name = "小可爱"
fmt.Printf("cat1的地址: %p \n\n",&cat1)
fmt.Printf("cat1.Name 的地址: %p \n",&cat1.Name)
fmt.Printf("cat1.Age 的地址: %p \n",&cat1.Age)
fmt.Printf("cat1.Color的地址: %p \n",&cat1.Color)
fmt.Printf("cat1.Hobby的地址: %p \n",&cat1.Hobby)
// cat1的地址: 0xc000020200 = &cat1.Name
// cat1.Name 的地址: 0xc000020200
// cat1.Age 的地址: 0xc000020210 0xc000020210 = 0xc000020200 + 16
// cat1.Color的地址: 0xc000020218 0xc000020218 = 0xc000020210 + 8
// cat1.Hobby的地址: 0xc000020228 0xc000020228 = 0xc000020218 + 16
//
//
// cat1 与 cat 值拷贝, 是两个独立的空间,其他一个修改,不影响对方
fmt.Println()
fmt.Printf("[修改之前]cat的地址: %p ,cat的值: %v \n\n",&cat,cat)
var cat2 *Cat = &cat
// cat2 := &cat
cat2.Name = "小美丽"
(*cat2).Color="黑色"
// *cat2.Color="黑色"
// 报错:因为点.运算符优先级比*高。
// *(cat2.Color)
cat.Hobby="贪玩(๑ŐдŐ)b"
fmt.Printf("cat2本身的地址: %p ,cat2的值(cat的地址): %p \n\n",&cat2,cat2)
fmt.Printf("cat2.Name 的地址: %p \n",&cat2.Name)
fmt.Printf("cat2.Age 的地址: %p \n",&cat2.Age)
fmt.Printf("cat2.Color的地址: %p \n",&cat2.Color)
fmt.Printf("cat2.Hobby的地址: %p \n",&cat2.Hobby)
fmt.Println()
fmt.Printf("[修改之后]cat的地址: %p ,cat的值: %v \n\n",&cat,cat)
fmt.Printf("cat.Name 的地址: %p \n",&cat.Name)
fmt.Printf("cat.Age 的地址: %p \n",&cat.Age)
fmt.Printf("cat.Color的地址: %p \n",&cat.Color)
fmt.Printf("cat.Hobby的地址: %p \n",&cat.Hobby)
// [修改之前]cat的地址: 0xc0000660c0 ,cat的值: {小喵喵 3 白色 吃<。)#)))≦}
// cat2本身的地址: 0xc000096020 ,cat2的值(cat的地址): 0xc0000660c0
// cat2.Name 的地址: 0xc0000660c0
// cat2.Age 的地址: 0xc0000660d0
// cat2.Color的地址: 0xc0000660d8
// cat2.Hobby的地址: 0xc0000660e8
// [修改之后]cat的地址: 0xc0000660c0 ,cat的值: {小美丽 3 黑色 贪玩(??д?)b}
// cat.Name 的地址: 0xc0000660c0
// cat.Age 的地址: 0xc0000660d0
// cat.Color的地址: 0xc0000660d8
// cat.Hobby的地址: 0xc0000660e8
}
func memoryStructInfo() {
r1 := Rect{Point{1,2},Point{3,4}}
fmt.Println()
fmt.Printf("r1的地址: %p \n\n",&r1)
fmt.Printf("r1.left.x 的地址: %p \n",&r1.left.x)
fmt.Printf("r1.left.y 的地址: %p \n",&r1.left.y)
fmt.Printf("r1.right.x 的地址: %p \n",&r1.right.x)
fmt.Printf("r1.right.y 的地址: %p \n",&r1.right.y)
// r1的地址: 0xc000012480
// r1.left.x 的地址: 0xc000012480
// r1.left.y 的地址: 0xc000012488
// r1.right.x 的地址: 0xc000012490
// r1.right.y 的地址: 0xc000012498
//
// 两个*Point类型的本身地址是连续的
// 指向的地址不一定连续的,编译器,系统分配
r2 := Rect2{&Point{10,20},&Point{30,40}}
fmt.Println()
fmt.Printf("r2的地址: %p \n\n",&r2)
fmt.Printf("r2.left 的本身地址: %p \n",&r2.left)
fmt.Printf("r2.right 的本身地址: %p \n",&r2.right)
// r2的地址: 0xc0000561c0
// r2.left 的本身地址: 0xc0000561c0
// r2.right 的本身地址: 0xc0000561c8
fmt.Printf("r2.left 的指向地址: %p \n",r2.left)
fmt.Printf("r2.right 的指向地址: %p \n",r2.right)
// r2.left 的指向地址: 0xc00000a100
// r2.right 的指向地址: 0xc00000a110
}
func jsonStruct() {
m1 := Monster{"白虎",1000,"沐浴圣光"}
jsonStr,err := json.Marshal(m1)
if err != nil {
fmt.Println("json处理错误 ",err)
}
// {"Name":"白虎","Age":1000,"Skill":"沐浴圣光"}
// {"name":"白虎","age":1000,"skill":"沐浴圣光"}
fmt.Println(string(jsonStr))
}
网友评论