01上节回顾
今日重点:结构体和文件操作
函数回顾
函数:一种代码组织形式
打印菱形,解决代码冗余问题,可维护性
package main import ( "fmt" "reflect" ) func foo() string { fmt.Println("foo...") return "foo" } func main() { //[3]int [4]int 长度为3的数组类型,长度为4的数组类型,不一样 var x=100 fmt.Println(x) fmt.Println(foo,reflect.TypeOf(foo)) //0xc6c560 打印出来一个地址 foo() bar:=foo //加括号,返回值赋给bar。不加括号把函数拷贝给bar bar() //存储的相同的内容,不是一块儿内存空间 }
上节核心考点值传递
参数回顾
示例1 参数
package main import ( "fmt" "reflect" ) func add(x,y int) int { return x+y } func main() { //参数 fmt.Println(add(1,5)) }
示例2 作用域
package main import "fmt" func add(a,b int) int { a=100 return a+b } func main() { //参数 var a,b=1,2 fmt.Println(add(a,b)) // 102 fmt.Println(a,b) // a和b还是1和2 注意作用域问题 }
指针类型回顾
取地址能做什么?
指针声明和赋值
package main import ( "fmt" "reflect" ) func main() { var x = "hello" //var p =&x var p *string p=&x //取址 fmt.Println(p,reflect.TypeOf(p)) //取值 *指针变量 fmt.Println(*p) //hello }
指针应用
指针应用1 没有使用指针时
package main import ( "fmt" "reflect" ) func bar(t int) { t=100 } func main() { //指针应用 var t = 1 bar(t) fmt.Println(t) } 打印结果还是1
指针应用2 打印出地址
package main import ( "fmt" ) func bar(p *int) { *p=100 fmt.Println("bar函数p地址",p) } func main() { //指针应用2 var t=1 var p =&t fmt.Println("main p地址",p) bar(p) }
图解
通过指向同一地址空间,实现修改
指针应用3 修改指针对应的值
package main import ( "fmt" ) func bar(p *int) { *p=100 fmt.Println("bar函数p地址",p) } func main() { //指针应用 var t=1 var p =&t fmt.Println("main p地址",p) bar(p) fmt.Println("main t",t) }
02 上节回顾2
匿名函数
匿名函数可以在使用函数的时候声明调用
package main import "fmt" func main() { //(1) (func() { fmt.Println("yuan") })() //(2) var z=(func(x,y int)int { return x+y })(1,2) fmt.Println(z) }
高阶函数
2个点
函数作为参数
函数作为返回值
函数作为参数
值拷贝,存的函数,拷贝函数,赋给f
package main func test02() { } func test01(f func()){ } func main() { test01(test02) }
函数作为返回值
outer为高阶函数
package main func outer() func() { return func() { } }
闭包
流程判断相关:循环、 if else 是否开辟作用域?? 开辟了作用域
package main import "fmt" func main() { if true { var x=100 fmt.Println(x) } fmt.Println(x) //报错,作用域问题 }
一个内部的函数,引用了外部的*变量
闭包函数一调用,返回匿名函数
不是闭包函数
没有引用外部非全局变量
//不是闭包函数 func biBao() func() { var ret=func(){ var x=10 fmt.Println(x) } return ret } func main() { f:=biBao() f() }
闭包函数
被引用的x,被保留下来了。
package main import "fmt" func biBao() func() { //闭包 var x=10 var ret=func(){ fmt.Println(x) } return ret }
闭包函数2 地址空间
var x=10 和x=100 用的是一块地址空间
package main import "fmt" func biBao() func() { //不是闭包函数 var x=10 fmt.Println(&x) var ret=func(){ x=100 fmt.Println(":::",&x) } return ret } func main() { f:=biBao() f() } 打印结果 0xc00000a0b8 ::: 0xc00000a0b8
内部使用x:=100,var x=10 和x:=100 用的不是一块地址
此时仍然是闭包函数,&x引用了外部*变量
package main import "fmt" func biBao() func() { //不是闭包函数 var x=10 fmt.Println(&x) var ret=func(){ fmt.Println(&x) x:=100 fmt.Println(":::",&x) } return ret } func main() { f:=biBao() f() } 打印结果 0xc000102058 0xc000102058 ::: 0xc000102090
作用域问题
x地址一样
func test2() { var x=10 fmt.Println(&x) if true { //if开辟作用域,也用了外部的变量 fmt.Println(x) } }
x地址不一样,又开辟了空间
func test() { var x=10 fmt.Println(&x) if true { //if开辟作用域,也用了外部的变量 var x=1 fmt.Println(x) } }
defer语句回顾
遇到return执行defer问题
03 编码小历史
编码
程序部分和存储部分分离
存储结构:内存和外存
CPU 运算器和控制器
输入和输出设备
高低电频
汇编语言:引入英文字母,极大提高性能。
编码系统:字母和二进制数字对应起来
ASCII表:最原始的编码表
利用多大空间存储:
bit位
8个bit位1字节 存256个二进制数字
ASCII表 用来127位
ASC扩展: 拉美使用了扩展位
0 000 0000
0 48 A 65 a 97
GBK- 用2个字节 65536个
0000 0000 0000 0000
---- ---- ---- ----
Unicode编码:一个符号4字节
0000 0000 0000 0000 0000 0000 0000 0000
UTF8编码(可伸缩的编码方式)
针对ASCII就用一个字节
针对汉字使用三个字节
package main import "fmt" func main() { var a='0' fmt.Println(a) var b = 48 fmt.Printf("%c",b) } 打印结果 48 0
04 Go的字符和字节
Go的字符与字节
byte就是字节,一个字节就是8个二进制位。uint8无符号整型,
byte和uint8本质没区别,都是ASCII码表的一个字符
package main import "fmt" func main() { var x uint8 x=255 fmt.Println(x) //255 var b byte b='A' fmt.Println(b) //65 fmt.Printf("%c:%d\n",b,b) //A:65 }
run占用4字节,32bit位,run本质和int32没区别,表示一个Unicode字符
package main import "fmt" func main() { var r rune r='a' fmt.Printf("%c:%d\n",r,r) //a:97 r='中' fmt.Printf("%c:%d\n",r,r) //中:20013 }
字符串和字节串转换
编码与解码
package main import ( "fmt" "reflect" ) func main() { //字符串与字节串之间的转换 var s="沙河" fmt.Println(s,reflect.TypeOf(s)) var b = []byte(s) fmt.Println(b,reflect.TypeOf(b)) //3个字节对应一个汉字 [230 178 153 230 178 179] []uint8 fmt.Println(string(b)) }
编码和解码
func main() { //编码 var s = "沙河" b:=[]byte(s) fmt.Println(b,reflect.TypeOf(b)) //解码 fmt.Println(string(b)) }
下午 05 字符串
遍历字符串
三要素for循环
func main() { //遍历字符串 //方式1 索引方式(会出现乱码) var hi= "hello 你好" for i:=0;i<len(hi);i++ { //fmt.Println(string(hi[i])) fmt.Printf("%c",hi[i]) } }
range
//遍历字符串 //方式2 用range方式遍历 for i,v:=range hi { fmt.Println(i,string(v)) } }
go语言中的字符串字符不可以修改
//go语言中的字符串字符不可以修改 fmt.Println(hi[0]) hi[0]='i' }
下午06 读文件
读文件:读到内存
写文件: 从内存写入
打开文件
var data = make([]byte,3) fmt.Println("data init",data) //data init [0 0 0]
首字母大写表示公开的,小写表示私有的
package main import ( "fmt" "os" ) func main() { //打开文件 var file,err=os.Open("天道") //报错处理 if err != nil { fmt.Println("err",err) } //延迟注册 defer file.Close() //读文件数据 var data = make([]byte,3) fmt.Println("data init",data) //data init [0 0 0] n,err:=file.Read(data) if err != nil { fmt.Println("err::",err) } fmt.Println("n:",n) //n: 3 }
1 按字节读文件(使用不多)
package main import ( "fmt" "os" ) func readBytes(file *os.File){ var data = make([]byte,3) fmt.Println("data init",data) n,err:=file.Read(data) if err != nil { fmt.Println("err::",err) } fmt.Println(n) fmt.Println("data:",string(data)) } func main() { //打开文件 var file,err=os.Open("天道") //报错处理 if err != nil { fmt.Println("err",err) } //延迟注册 defer file.Close() //按字节读文件数据 readBytes(file) }
2 按字符串读
示例1
分隔符,字节类型
打印换行问题
原内容有换行,println又增加了一个换行,使用print fmt.Print(line)
package main import ( "bufio" "fmt" "io" "os" ) func main() { //打开文件 var file, err = os.Open("天道") //报错处理 if err != nil { fmt.Println("err", err) } //延迟注册 defer file.Close() //(2)按字符串 reader:=bufio.NewReader(file) for true { line,err:=reader.ReadString('\n') fmt.Print(line) if err==io.EOF { break } } }
示例2 放入函数中
package main import ( "bufio" "fmt" "io" "os" ) func readString(file *os.File) { reader:=bufio.NewReader(file) for true { line,err:=reader.ReadString('\n') fmt.Print(line) if err==io.EOF { break } } } func main() { //打开文件 var file, err = os.Open("天道") //报错处理 if err != nil { fmt.Println("err", err) } //延迟注册 defer file.Close() //(2)按字符串 readString(file) }
3 读取整个文件
package main import ( "fmt" "io/ioutil" "os" ) func main() { //打开文件 var file, err = os.Open("天道") //报错处理 if err != nil { fmt.Println("err", err) } //延迟注册 defer file.Close() //(3)读取整个文件 content,err:=ioutil.ReadFile("天道") fmt.Println(string(content)) }
注意:文件中有空行符就都会打印
下午07 写文件
1 写字节
打开文件OpenFile
package main import ( "fmt" "os" ) func main() { //文件名 模式 权限 file,err:=os.OpenFile("天道2",os.O_CREATE|os.O_WRONLY|os.O_TRUNC,0666) if err != nil { fmt.Println("open file failed,err",err) } defer file.Close() //写字节 var s="悟道休言天命2" //file.Write([]byte(s)) //写字节 file.WriteString(s) }
2 写字符串
package main import ( "bufio" "fmt" "os" ) func main() { //文件名 模式 权限 file,err:=os.OpenFile("天道2",os.O_CREATE|os.O_WRONLY|os.O_TRUNC,0666) if err != nil { fmt.Println("open file failed,err",err) } defer file.Close() //(2)写字符串 writer:=bufio.NewWriter(file) writer.WriteString("修行勿取真经。") //更新磁盘 writer.Flush() }
3写文件
WriteFile是覆盖,文件不存在时,会创建
package main import ( "io/ioutil" ) func main() { //(3) s:=` 悟道休言天命 修行勿取真经` ioutil.WriteFile("天道3",[]byte(s),0666) }
下午08 声明结构体并实例化
声明结构体
格式
字段名必须唯一,可以通过逗号隔开
type 类型名 struct { //标识结构体的类型名,在同一个包内不能重复 字段1 字段1类型 //字段名必须唯一 字段2 字段2类型 }
同类型的变量也可以写在一行,用逗号隔开
type Book struct { title,author string price int }
示例
//声明一个结构体 type Student struct { name string //结构体的成员变量 age int score map[string]int }
实例结构体对象
结构体和结构体的实例对象
先有对象,具有相同属性和行为的对象,称为类。
有这些属性的个体,称为对象。
方式1 先声明,再赋值
package main import "fmt" //声明一个结构体 type Student struct { name string //结构体的成员变量 age int score map[string]int } func main() { //实例结构体对象 //方式1 直接声明 先声明,再赋值 var s Student //结构体是值类型 fmt.Println("s",s) //s { 0 map[]} }
图示:开辟内存空间
赋值
package main import "fmt" //声明一个结构体 type Student struct { name string //结构体的成员变量 age int score map[string]int } func main() { //实例结构体对象,支持.操作 //方式1 先声明,再赋值 var s Student //结构体是值类型 fmt.Println("s", s) //s { 0 map[]} s.name = "zhangsan" s.age = 22 s.score = map[string]int{"语文": 95, "数学": 98, "英语": 93} fmt.Println(s.age) //22 fmt.Println(s) //{zhangsan 22 map[数学:98 英语:93 语文:95]} }
下午 09 结构体实例化方式
方式2 声明并赋值(键值对赋值)
package main import "fmt" //声明一个结构体 type Student struct { name string age int score map[string]int } func main() { //实例结构体对象,支持.操作 //方式2 声明并赋值 var s2 Student s2 = Student{name: "rain", age: 32, score: map[string]int{"语文": 100, "数学": 90, "英语": 80}} fmt.Println(s2) //{rain 32 map[数学:90 英语:80 语文:100]} fmt.Println(s2.age) //32 fmt.Println(s2.score["数学"]) //90 }
方式3 声明并赋值(多值赋值)
//方式3 声明并赋值 多值赋值 s3:=Student{"alvin",18, map[string]int{"yuwen":100,"shuxue":90,"yingyu":89}} fmt.Println(s3) }
s3的地址和s3.name的地址一样吗?
一样
package main import "fmt" //声明一个结构体 type Student struct { name string age int score map[string]int } func main() { //实例结构体对象,支持.操作 //方式3 声明并赋值 多值赋值 s3:=Student{"alvin",18, map[string]int{"yuwen":100,"shuxue":90,"yingyu":89}} fmt.Println(s3) fmt.Printf("%p,%p\n",&s3,&s3.name) //0xc0000444a0,0xc0000444a0 }
练习中的思考
练习补充1:结构体中切片元素添加
对学生管理结构体中添加学生成绩
package main import "fmt" type Student struct { Name string //结构体成员变量 Age int Score [3]int } type StudentManager struct { AllStu []Student } func main() { smm:=StudentManager{[]Student{}} var stu1 Student=Student{"张三",18,[3]int{90,98,97}} stu2:=Student{"李四",19,[3]int{91,92,93}} stu3:=Student{"zhngsan",20,[3]int{99,98,95}} smm.AllStu=append(smm.AllStu,stu1) smm.AllStu=append(smm.AllStu,stu2) smm.AllStu=append(smm.AllStu,stu3) fmt.Println(smm) } 打印结果 {[{张三 18 [90 98 97]} {李四 19 [91 92 93]} {zhngsan 20 [99 98 95]}]}
练习补充2:结构体中map对象添加元素(开辟空间)
package main import "fmt" type Student struct { Name string Age int score [3]int } type StuManager struct { Id int allStu map[string]Student } func main() { smm:=StuManager{} //需要先开辟空间,否则报错 smm.allStu=make(map[string]Student) fmt.Println(smm) stu1:=Student{"zhangsan",19,[3]int{90,98,97}} smm.Id=1001 smm.allStu["1001"]=stu1 stu2:=Student{"lisi",20,[3]int{80,90,95}} //注意:Id是值元素,再赋值时覆盖 smm.Id=1002 //map元素 不存在时添加,存在时修改 smm.allStu["1002"]=stu2 //stu3:=Student{"lisi",20,[3]int{80,90,95}} //smm.allStu["1001"]=stu3 //会覆盖map键对应"1001"的值 fmt.Println(smm) //{1002 map[1001:{zhangsan 19 [90 98 97]} 1002:{lisi 20 [80 90 95]}]} }
练习补充3:结构体中map对象添加元素2(开辟空间)
有两个学生对象,添加到结构体中(结构体中对象是map类型)
package main import "fmt" type Student struct { Name string Age int score [3]int } type StuManager struct { allStu map[string]Student } func main() { smm:=StuManager{} /* //需要先开辟空间,否则报错 smm.allStu=make(map[string]Student) fmt.Println(smm)*/ stu1:=Student{"zhangsan",19,[3]int{90,98,97}} stu2:=Student{"lisi",20,[3]int{80,90,95}} //smm.allStu["1001"]=stu1 s1:=map[string]Student{"1001":stu1} s2:=map[string]Student{"1002":stu2} //当有两个学生对象,如何加入结构体?还是需要先开辟空间,再遍历 /* //这种会导致覆盖 smm.allStu=s1 smm.allStu=s2*/ smm.allStu=make(map[string]Student) for k,v:=range s1 { smm.allStu[k]=v } for k,v:=range s2 { smm.allStu[k]=v } fmt.Println(smm) //{map[1001:{zhangsan 19 [90 98 97]} 1002:{lisi 20 [80 90 95]}]} }
练习补充4:再回顾map
如果不是声明并赋值map[string]string{“1001”:stu1}这种使用map的方式,
直接使用map[“1001”]=stu1需开辟空间
package main import "fmt" func main() { var smm map[string]map[string]string stu1:=map[string]string{"sid":"1001","name":"zhangsan","age":"18","yuwen":"99","shuxue":"98","yingyu":"95"} smm= map[string]map[string]string{"1001":stu1} //smm["1001"]=stu1 //这种报错,没有开辟空间 stu2:=map[string]string{"sid":"1002","name":"lisi","age":"19","yuwen":"99","shuxue":"98","yingyu":"95"} smm["1002"]=stu2 fmt.Println(smm) }
下午10 结构体的指针变量
值拷贝
变量赋值后,修改s2,s.name发生变化吗? 不变,已经是不同的地址空间
package main import "fmt" //声明一个结构体 type Student struct { name string age int score map[string]int } func main() { var s=Student{name:"rain",age: 30,score: map[string]int{"语文":100,"数学":90,"英语":80}} s2:=s s2.name="yuan" fmt.Println(s.name) }
图解
值拷贝,函数传入结构体指针
package main import "fmt" //声明一个结构体 type Student struct { name string age int score map[string]int } func foo(p *Student) { //如果p是一个结构体的指针变量,name执行p.name的时候,编译器会翻译成(*p).name p.name="yuan" fmt.Println(*p) //(*p).name = "yuan" } func main() { //s是一个结构体对象 var s=Student{name:"rain",age: 30,score: map[string]int{"语文":100,"数学":90,"英语":80}} //案例1 /*s2:=s s2.name="yuan" fmt.Println(s.name)*/ /* //案例2 foo(s) fmt.Println(s) //不变 {rain 30 map[数学:90 英语:80 语文:100]}*/ //案例2 var p=&s //是一个Student结构体的指针对象 foo(p) fmt.Println(s) }
下午11 模拟构造函数
示例1 通过调用函数,获取结构体对象
package main import "fmt" type Student struct { name string age int score map[string]int } func NewStudent(name string,age int,score map[string]int) Student{ return Student{name:name,age:age,score: score} } func main() { //var s = Student{name: "rain", age: 32, score: map[string]int{"yuwen": 100, "shuxue": 90, "yingyu": 80}} s:=NewStudent("zhangsan",18, map[string]int{"语文":100,"数学":90,"英语":89}) fmt.Println(s) //{zhangsan 18 map[数学:90 英语:89 语文:100]} }
示例2
package main import "fmt" type Student struct { name string // 结构体的成员变量 age int score map[string]int } func NewStudent(name string,age int,score map[string]int) *Student { return &Student{name:name,age:age,score:score} } func main() { s:=NewStudent("yuan",23, map[string]int{"yuwen":100,"shuxue":90,"yingyu":89}) fmt.Println(s) fmt.Println(s.name) }
下午12 方法接收器
示例1 声明结构体
package main //声明一个结构体 type Player struct { name string //结构体的成员变量 healthPoint int magic int } func NewPlayer(name string,healthPoint int,magic int) *Player { return &Player{name:name,healthPoint: healthPoint,magic: magic} } func main() { p:=NewPlay("yuan",100,80) fmt.Println(p.name) fmt.Println(p.healthyPoint) } 打印结果 yuan 100
示例2 声明接收器方法
调用是会把yuan赋值给小p
这时候用p.name
package main import "fmt" //声明一个结构体 type Player struct { name string //结构体的成员变量 healthPoint int magic int } func NewPlayer(name string,healthPoint int,magic int) *Player { return &Player{name:name,healthPoint: healthPoint,magic: magic} } func (p Player)attack() { fmt.Println(p.name,"发起攻击") } func (p Player)attacked() { fmt.Println("被攻击") } func main(){ yuan:=NewPlayer("yuan",100,100) rain:=NewPlayer("rain",100,100) yuan.attack() rain.attack() } 打印结果 yuan 发起攻击 rain 被攻击
示例3 修改修改被攻击的对象
package main import "fmt" type Player struct { name string healthyPoint int magic int } func (p Player)attack() { fmt.Println(p.name,"发起攻击") } func (p Player)attacked() { fmt.Println(p.name,"被攻击") p.healthyPoint=p.healthyPoint-30 }
图示
执行rain.attacked时,rain发生值拷贝,开辟p空间
执行 -30,p发生-30操作
示例4 对外部的值做操作,传指针。
package main import "fmt" //声明一个结构体 type Player struct { name string //结构体的成员变量 healthPoint int magic int } func NewPlayer(name string,healthPoint int,magic int) *Player { return &Player{name:name,healthPoint: healthPoint,magic: magic} } func (p Player)attack() { fmt.Println(p.name,"发起攻击") } func (p *Player)attacked() { fmt.Println("被攻击") p.healthPoint=p.healthPoint-30 } func main(){ yuan:=NewPlayer("yuan",100,100) rain:=NewPlayer("rain",100,100) yuan.attack() rain.attacked() fmt.Println(rain.healthPoint) }
下午13 json序列化
是一种数据交换格式
go语言数据类型 |
json支持的类型 |
整型、浮点型 |
整型、浮点型 |
字符串(双引号) |
字符串双引号 |
逻辑值(true或false) |
逻辑值(true或false) |
数组,切片 |
数组(在方括号中) |
map |
对象(再花括号中) |
nil |
null |
示例1 map序列化
package main import ( "encoding/json" "fmt" ) func main(){ //var map01 = map[int]string{1:"111",2:"222",3:"333"} var map01=map[string]interface{}{"name":"yuan","isMarried":false,"score":[3]int{100,90,89}} content,_:=json.Marshal(map01) fmt.Println(string(content)) //{"isMarried":false,"name":"yuan","score":[100,90,89]} }
示例2 struct序列化
package main import ( "encoding/json" "fmt" ) type Student struct { name string age int score [3]int } func main() { s:=Student{ name:"yuan", age:22, score: [3]int{1,2,3}, } content,_:=json.Marshal(s) fmt.Println(string(content)) //{} }
会打印出来空的,为什么空?
小写,是私有的
需要首字母大写
package main import ( "encoding/json" "fmt" ) type Student struct { Name string //结构体成员变量 Age int Score [3]int } func main() { s:=Student{ Name:"yuan", Age:22, Score: [3]int{1,2,3}, } content,_:=json.Marshal(s) fmt.Println(string(content)) //{"Name":"yuan","Age":22,"Score":[1,2,3]} }
序列化后,写入文件中
package main import ( "encoding/json" "fmt" "io/ioutil" ) type Student struct { Name string //结构体成员变量 Age int Score [3]int } func main() { s:=Student{ Name:"yuan", Age:22, Score: [3]int{1,2,3}, } content,_:=json.Marshal(s) fmt.Println(string(content)) //{"Name":"yuan","Age":22,"Score":[1,2,3]} //写入文件中 //ioutil.WriteFile("data.txt",[]byte(s),0666) //结构体不能直接转 ioutil.WriteFile("data.txt",content,0666) }
读文件
读取出来是字符串
package main import ( "fmt" "io/ioutil" ) func main() { //读文件 content,_:=ioutil.ReadFile("data.txt") fmt.Println(string(content)) //{"name":"yuan","age":18,"score":[1,2,3]} }
data.txt文件内容
{"name":"yuan","age":18,"score":[1,2,3]}
反序列化
Unmarshal(字节串,&结构体)
不加&符,发生值拷贝,目的是需要改s2对应的值(即通过指针,修改)
package main import ( "encoding/json" "fmt" "io/ioutil" ) type Student struct { Name string `json:"name"` Age int `json:"age"` Score [3]int `json:"score"` } func NewStudent(name string, age int, score [3]int) Student { return Student{Name: name, Age: age, Score: score} } func main() { //读文件 content,_:=ioutil.ReadFile("data.txt") //fmt.Println(string(content)) //{"name":"yuan","age":18,"score":[1,2,3]} //反序列化 json字符串转换成golang支持的数据类型 var s Student json.Unmarshal(content,&s) fmt.Println(s) //{yuan 18 [1 2 3]} fmt.Println(s.Name) //yuan fmt.Println(s.Age) // 18 }
go与js代码交换
JSON.stringify(s)
package main import ( "encoding/json" "fmt" ) func main() { //go与js进行json交换 s1:=`{"name":"yuan","age":18,"gf":null}` var m1=make(map[string]interface{}) json.Unmarshal([]byte(s1),&m1) fmt.Println(m1) fmt.Println(m1["name"]) } 打印结果 map[age:18 gf:<nil> name:yuan] yuan
问题
文件中存的是单引号,是否有影响?
{"name":'yuan',"age":18,"score":[1,2,3]}
是字符串,不是json字符串,
Unmarshal之前必须给个json字符串
package main import ( "encoding/json" "fmt" "io/ioutil" ) type Student struct { Name string `json:"name"` Age int `json:"age"` Score [3]int `json:"score"` } func main() { content,_:=ioutil.ReadFile("data.txt") fmt.Println(string(content)) //{"name":'yuan',"age":18,"score":[1,2,3]} var stu Student json.Unmarshal(content,&stu) fmt.Println(stu) //{ 0 [0 0 0]} 换成单引号,不是json字符串,打印默认值 }
作业:结构体版 学生管理系统
1、结构体实现
2、持久化