Day05 Go语言文件操作,结构体,构造函数,方法接收器,json序列化

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)
}

图解

通过指向同一地址空间,实现修改

Day05 Go语言文件操作,结构体,构造函数,方法接收器,json序列化

 

指针应用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[]}
}

图示:开辟内存空间

Day05 Go语言文件操作,结构体,构造函数,方法接收器,json序列化

 

 

 

赋值

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)
}

 

图解

Day05 Go语言文件操作,结构体,构造函数,方法接收器,json序列化

 

 

 

值拷贝,函数传入结构体指针

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操作

Day05 Go语言文件操作,结构体,构造函数,方法接收器,json序列化

 

 

示例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)

Day05 Go语言文件操作,结构体,构造函数,方法接收器,json序列化

 

 

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、持久化

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

上一篇:Day04 Go语言函数:值传递、匿名函数、高阶函数、闭包和defer语句


下一篇:2021最新阿里代码规范(前端篇)