Go语言学习(二)

1、递归
递归:自己调用自己
递归适合处理那种问题相同,问题的规模越来越小的场景
递归一定要有一个明确的退出条件

func main(){
	fmt.Println(f(5))
}

func f(n uint64) uint64{
	if n == 1{
		return 1
	}
	return n * f(n-1)
} 

2、定义类型和定义别名

//自定义类型
type myint int
//定义别名
type youint = int

func main(){
	var n myint
	n = 100
	fmt.Println(n)
	fmt.Printf("%T\n",n)

	var m youint
	m = 500
	fmt.Println(m)
	fmt.Printf("%T\n",m)
}

效果如下所示:

PS D:\go> go run f.go
100
main.myint
500
int

3、匿名结构体
要理解匿名结构体的应用方向

func main() {
	//匿名结构体主要是用于临时场景
    var s struct {
		name string
		age int
	}
	s.name="超峰"
	s.age = 20
	fmt.Printf("%v\n",s)
}

4、创建指针类型的结构体


type person  struct{
	name,sex string
}

// go语言里面函数永远传的是拷贝
func f(p person){
	p.sex = "女"   // 修改额是副本的sex,而不是原来的sex
}

func f1(p *person){
	//(*p).sex = "女"   //根据内存地址找到哪个变量,修改的就是原来的变量
	p.sex = "女"  //跟上面的都是一个效果,程序会自动判断p是什么类型,自动转化成(*p),这是语法糖
}


func main() {
	var p person
	p.name ="超峰"
	p.sex = "男"
	f(p)
	fmt.Println(p.sex)
	f1(&p)
	fmt.Println(p.sex)
}

效果如下:

PS D:\go> .\f.exe
男
女

指针类型分析

func main(){
	var a = 10
	b := &a
	fmt.Printf("%T\n",b)    //打印b的类型
	fmt.Printf("%p\n",b)   //以十六进制显示  ,b指针保存的是a的内存地址
	fmt.Printf("%v\n",b)   //以默认格式显示
	fmt.Printf("%p\n",&b)   //打印b指针对应的内存地址,因为b指针也有自己的内存地址
}

效果如下所示:

PS D:\go> .\g.exe        
*int
0xc0000ac068
0xc0000ac068
0xc0000d8018

结构体类型的指针

type person  struct{
	name,sex string
}


func main() {
	//结构体指针1
	var p2 = new(person)    //p2是一个指针类型的结构体
	p2.sex = "男"
	fmt.Printf("%s\n",(*p2).sex)
	fmt.Printf("%s\n",p2.sex)
	fmt.Printf("%T\n",p2)    //得到指针类型
	fmt.Printf("%p\n",p2)      //p2保存的就是一个内存地址
	fmt.Printf("%p\n",&p2)     //求p2的内存地址

	//结构体指针2
	// 2.1、key-value方式初始化
	var p3 = person{
		name: "特朗普",
		sex: "男",
	}
	fmt.Printf("%#v\n",p3)

	// 2.2、值传递的方式初始化
	var p4 = person{
		"小王子",
		"男",
	}
	fmt.Printf("%#v\n",p4)
}

效果如下所示:

PS D:\go> .\f.exe
男
男
*main.person
0xc00005c3c0
0xc000006028
main.person{name:"特朗普", sex:"男"}
main.person{name:"小王子", sex:"男"}

5、构造函数

type person struct{
	name string
	age int
}

type dog struct{
	name string
}

//构造函数:约定俗称用new开头
//返回的是结构体还是结构体指针
//当结构体比较大的上海尽量使用结构体指针,减少程序的内存开销
func newPerson(name string, age int) *person{
	return &person {
		name: name,
		age : age,
	}
}

func newdog(name string) dog{
	return dog{
		name: name,
	}
}

func main(){
	res1 := newPerson("超峰",20)
	fmt.Println(*res1)
	res2 := newdog("Mike")
	fmt.Println(res2)
}

效果如下所示:

PS D:\go> .\f.exe
{超峰 20}
{Mike}

构造函数和方法区别

type dog struct {
	name string

}


// 构造函数
func newDog(name string) dog{
	return dog{
		name: name,
	}
}

//方法是作用于特定类型的函数
// 接受者表示的是调用该方法的具体类型变量,多用类型名首字母小写表示,不建议使用this,self来表示
func (d dog) wang(){
	fmt.Printf("%s: 汪汪汪",d.name)
}

func main(){
	d1 := newDog("Mike")
	d1.wang()
}

效果如下所示L:

PS D:\go> .\g.exe
Mike: 汪汪汪

5、值传递和指针传递的区别
先说说什么时候应该使用指针类型的接收者
a、需要修改接收者中的值
b、接收者是拷贝代码比较大的对象
c、保证一致性,如果使用了指针传递的方式,尽量都使用这种方法

举个例子:

package main

import "fmt"

type dog struct{
	name string
}

type person struct{
	name string
	age int
}

func newPerson(name string,age int) person{
	return person{
		name: name,
		age: age,
	}
}

func newDog(name string) dog{
	return dog{
		name: name,
	}
}

// 使用值接收者:传拷贝进去
func (d dog)wang(){
	fmt.Printf("%s:汪汪汪\n",d.name)
}

// 指针接收者:传内存地址进去
func (p *person)guonian(){
	p.age++
}

func main(){
	d1 := newDog("Mike")
	d1.wang()
	p1 := newPerson("John",20)
	p1.guonian()   //相当于把p1的地址传到guonian()这个函数里面,这样子写比较好理解(&p1).guonian(),但实际上不这样用
	fmt.Println(p1.name,p1.age)
}

效果如下所示:

PS D:\go> .\f.exe
Mike:汪汪汪
John 21

顺便补充一个自定义类型的知识点

// 不能给别的包里面的类型增加自定义方法,只能给自己的包里的类型添加方法
type myint int
func (m myint) f1(){
	fmt.Println("hello")
}

func main(){
	m := myint(100)  // 与int(100)类似的效果。
	m.hello
}

函数版学生管理系统

package main

import (
	"fmt"
	"os"
)

type student struct{
	id int
	name string
}

var (
	allstudent map[int]*student   //变量声明
)

func showAllstudent() {
	for k,v := range allstudent{  // map里面存储的是 map[1:{1,"Mike"},2:{2:"John"}]
		fmt.Printf("学生id是: %d, 姓名是: %s\n",k,v.name)  
	}
}

func newstu(id int,name string) *student{
	return &student{
		name: name,
		id: id,
	}
}

func addstudent() {
	var (
		id int
		name string
	)
	fmt.Print("请输入增加的学号id: ")
	fmt.Scanln(&id)
	fmt.Print("请输入增加的学生姓名: ")
	fmt.Scanln(&name)
	stu := newstu(id,name)
	allstudent[id] = stu
	fmt.Println("增加成功")
}

func deletestudent(){
	var (
		id int
	)
	fmt.Print("请输入你要删除的学号id: ")
	fmt.Scanln(&id)
	delete(allstudent,id)
	fmt.Println("删除成功")
}

func main(){
	allstudent  = make(map[int]*student,48)
	for{
		fmt.Printf("欢迎来到学生管理系统")
		fmt.Println(`
		1、查看所有学生
		2、增加学生
		3、删除学生
		4、退出
		`)

		fmt.Printf("请输入你要操作的序号: ")
		var choice int
		fmt.Scanln(&choice)
	//	fmt.Printf("你当前输入的序号是: %d",choice)

		switch choice {
		case 1:
			showAllstudent()
		case 2:
			addstudent()
		case 3:
			deletestudent()
		case 4:
			os.Exit(1)
		default:
			fmt.Println("滚")
		}
	}
}

6、匿名结构体

package main

import (
	"fmt"
)

type address struct{
	provice string
	city string
}


type person struct{
	name string
	age int
	addr address
}
type company struct{
	name string
	addr address
}
func main(){
	p1 := person {
		name: "Mike",
		age: 20,
		addr: address{
			provice: "北京",
			city: "朝阳",
		},
	}

	c1 := company {
		name: "牛卡福",
		addr: address {
			provice: "北京",
			city: "朝阳",
		},
	}

	fmt.Println(p1)
	fmt.Println(p1.name,p1.addr.city,p1.addr.provice)
	fmt.Println("----------------------------")
	fmt.Println(c1)
	fmt.Println(c1.name,c1.addr.provice)
}

7、结构体之继承
如下例子所示:狗继承了动物会走的特性,狗调用自己会叫的特性,同时继承了动物会走的特性

type animal struct{
	name string
}

func (a animal) move(){
	fmt.Printf("%s会动\n",a.name)
}

type dog struct {
	feet uint8
	animal
}

func (d dog)wang(){
	fmt.Printf("%s会叫: 汪汪汪\n",d.name)
}

func main(){
	f1 := animal{name: "动物"}
	f1.move()
	f2 := dog{
		feet: 4,
		animal: animal{
			name: "狗",
		},
	}
	f2.wang()
	f2.move()
}

效果如下所示:

PS D:\go> .\i.exe        
动物会动
狗会叫: 汪汪汪
狗会动

8、结构体与json
1、序列化:把Go语言中的结构体变量转化为json格式的字符串
2、反序列化:把json格式的字符串转化为Go语言中能够识别的结构体变量

例子:

package main

import (
	"fmt"
	"encoding/json"
)

type person struct {
	name string
	age int
}

func main(){
	p1 := person{
		name: "Mike",
		age: 18,
	}
	b,err := json.Marshal(p1)
	if err != nil{
		fmt.Printf("Marshal failed, err: %v",err)
		return
	}
	// 将返回的字节强转为string字符串
	fmt.Printf("%#v\n",string(b))
}

效果如下所示:

PS D:\go> .\i.exe
"{}"

我们使用了%#v,这是以go语法来进行了打印。看的出来是转化成了字符串。
但是我们发现里面的json字串是空的,这是因为结构体的字段名需要大写,我们是把main包里面的结构体字段传入到json包里面,字段小写的话是穿不了的,需要改成首字母大写的形式,如下所示:

# 这里只修改部分代码即可
type person struct {
	Name string
	Age int
}

效果如下所示

PS D:\go> .\i.exe        
"{\"Name\":\"Mike\",\"Age\":18}"

看的出来现在已经转化了,比较成功。
可以把%#v改成%v,这样子的话打印出来的结果里面就不会有双引号了,是默认打印的结果,如下所示

PS D:\go> .\i.exe        
{"Name":"Mike","Age":18}

上面这种用法会用在前后端的交互中,有时候前端要接收全部小写的单词,那么我们上面是返回的结果是首字母大写的字段,所以这是不行的,可以如下所示进行修改

type person struct {
	Name string `json:"name"`
	Age int 	`json:"age"`
}
# 后面都不需要修改,再看下效果

效果

PS D:\go> .\i.exe        
{"name":"Mike","age":18}

这返回的结果中,就是小写了,符合前端需要的标准

接下来演示反序列化的代码

package main

import (
	"fmt"
	"encoding/json"
)

type person struct {
	Name string `json:"name"`
	Age int 	`json:"age"`
}

func main(){
	p1 := person{
		Name: "Mike",
		Age: 18,
	}
	b,err := json.Marshal(p1)
	if err != nil{
		fmt.Printf("Marshal failed, err: %v",err)
		return
	}
	// 将返回的字节强转为string字符串
	fmt.Printf("%v\n",string(b))

	//反序列化
	str := `{"name":"John","age":20}`
	var p2 person

	json.Unmarshal([]byte(str), &p2)   //注意这里需要传入指针,传指针式为了能在json.Unmarshal内部修改p2的值
	fmt.Printf("%v\n", p2)
}

效果如下所示:

PS D:\go> .\i.exe
{"name":"Mike","age":18}
{John 20}

知识点总结:
1、架构体内部的字段首字母要大写,不大写别人是访问不道德
2、反序列化需要传递指针

回顾和总结

package main

import (
	"fmt"
)

type tmp struct{
	id int
	name string
}

type person struct{
	name string
	age int
}

func newPerson(name string,age int) person {
	return person{
		name: name,
		age: age,
	}
}

//只有接收者类型的变量才可以调用
func (p person)hoppy(str string){
	fmt.Printf("%s的爱好是: %s\n",p.name,str)
}

//下面这种是修改的结构体的副本
func (p person)guonian2(){
	p.age++
}

//指针接收者,强烈建议使用
//当需要修改结构体的变量的值的时候,就可以使用指针接收者
func (p *person)guonian(){
	p.age++
}

func main(){
	var b = tmp{100,"John"}
	fmt.Println(b)

	var a = struct{
		id int
		name string
	}{10,"Mike"}
	fmt.Println(a)

	// 结构体的实例化的三种方法
	var p1 person
	p1.name = "John"
	p1.age = 20

	//匿名返回值
	p2 := person{"Simon",30}

	//构造函数返回值,返回值的是对应结构体类型
	p3 := newPerson("Mike",40)
	fmt.Println(p1,p2,p3)

	p1.hoppy("羽毛球")
	p2.hoppy("篮球")
	p3.hoppy("网球")

	p1.guonian()
	p2.guonian()
	p3.guonian()
	fmt.Println(p1,p2,p3)

	var f = "Mike"
	fmt.Printf("%v",[]byte(f))
}

效果如下所示:

PS D:\go> go build .\k.go
PS D:\go> .\k.exe        
{100 John}
{10 Mike}
{John 20} {Simon 30} {Mike 40}
John的爱好是: 羽毛球
Simon的爱好是: 篮球
Mike的爱好是: 网球
{John 21} {Simon 31} {Mike 41}
[77 105 107 101]

补充两个知识点
1、类型别名只是在代码编写过程周有效,编译完成转换就不存在
2、内置的byte和rune都是类型别名
3、字符串类型可以和byte类型的切片进行转换

9、接口
接口的定义

type 接口名 interface {
  方法名1(参数1, 参数2....)(返回值1,返回值2...)
  方法名2(参数1, 参数2....)(返回值1,返回值2...)
  ......
}

接口的实现
一个变量如果实现了接口中规定的所有的方法,那么这个变量就实现了这个接口,可以称为这个接口类型的变量

type animal interface {
	move()
	eat(string)
}

type cat struct{
	name string
	feet int8
}

func (c cat)move(){
	fmt.Println("猫会动")
}

func (c cat)eat(s string){
	fmt.Printf("猫吃%s\n",s)
}


type chicken struct{
	feet int8
}

func (c chicken) move(){
	fmt.Println("鸡会动")
}

func (c chicken)eat(s string){
	fmt.Printf("鸡吃%s\n",s)
}

func main(){
	var a1 animal //定义一个接口类型的变量,默认是nil

	bc := cat{   //定义一个cat类型的变量bc
		name: "蓝猫",
		feet: 4,
	}

	a1 = bc
	fmt.Println(a1)
	a1.move()
	a1.eat("猫粮")
	//查看类型
	fmt.Printf("%T\n",a1)
}

效果如下:

PS D:\go> .\l.exe      
{蓝猫 4}
猫会动
猫吃猫粮
main.cat

10、使用值接收者实现接口与使用指针接收者实现接口的的方法

使用值接收者实现接口,结构体类型和结构体指针类型的变量都能存
使用指针接收者实现接口只能存结构体指针类型的变量

type animal interface {
	move()
	eat(string)
}

type cat struct{
	name string
	feet int8
}

//使用指针接收者实现了接口的所有方法
func (c *cat)move(){
	fmt.Println("猫会动")
}

func (c *cat)eat(s string){
	fmt.Printf("猫吃%s\n",s)
}


type chicken struct{
	feet int8
}

func (c chicken) move(){
	fmt.Println("鸡会动")
}

func (c chicken)eat(s string){
	fmt.Printf("鸡吃%s\n",s)
}

func main(){
	var a1 animal //定义一个接口类型的变量,默认是nil

	bc := cat{   //定义一个cat类型的变量bc
		name: "蓝猫",
		feet: 4,
	}

	a1 = &bc  //实现animal这个接口的cat的指针类型
	fmt.Println(a1)
	a1.move()
	a1.eat("猫粮")

        bc1 := &cat{name:"白猫",feet:4}
	a1 = bc1
	a1.move()
	a1.eat("小鱼干")

}

效果如下所示L:

PS D:\go> .\l.exe      
&{蓝猫 4}
猫会动
猫吃猫粮
猫会动
猫吃小鱼干

接口嵌套

type Animal1 interface {
	SetName(string)
}

type Animal2 interface {
	GetName() string
}

type Animal interface{
	Animal1
	Animal2
}

type Dog struct{
	name string
}

func (d *Dog)SetName(name string){
	d.name = name
}

func (d *Dog)GetName()string{
	return d.name
}

func main(){
	var dog = &Dog{name:"Mike",}
	var d Animal
	d = dog
	d.SetName("小狗")
	fmt.Println(d.GetName())
}

效果如下所示:

PS D:\go> .\l.exe
小狗

匿名函数的补充
匿名函数就是没有名字的函数

func main(){
	f := func(i int){
		fmt.Printf("Hello: %d\n",i)
	}
	f(2)

	f1 := func(i int){
		fmt.Printf("结果是: %d\n",i*i*i)
	}
	f1(3)

}

效果如下所示:

PS D:\go> .\l.exe      
Hello: 2
结果是: 27

11、空接口
当不知道保存什么类型的值的时候,可以定义一个空接口类型

func main(){
	var a map[string]interface{}
	a = make(map[string]interface{},48)
	a["name"] = "Mike"
	a["年龄"] =  20
	a["hobby"] = [...]string{"唱","跳","rap"}
	fmt.Println(a)

}

效果如下所示:

PS D:\go> .\l.exe
map[hobby:[唱 跳 rap] name:Mike 年龄:20]

类型断言:
主要是使用变量.(类型)方式来判定

func main(){
	var a interface{}   //声明一个空接口类型
	a = 100   //此时a是int64类型的
	v1,ok := a.(int8)
	if ok{
		fmt.Println("猜对了,是int8类型",v1)
	}else {
		fmt.Println("猜错了")
	}

	//第二种方式,使用类型断言,用type判断这是什么类型
	switch v2 := a.(type) {
	case int8:
		fmt.Println("int8",v2)
	case int16:
		fmt.Println("int16",v2)
	case int32:
		fmt.Println("int32",v2)
	case int64:
		fmt.Println("int64",v2)
	case string:
		fmt.Println("string",v2)
	case int:
		fmt.Println("int",v2)
	}
}

效果如下所示:

PS D:\go> .\n.exe
猜错了
int 100

12、包package
如果想在一个包中引用另外一个包里面的标识符(如变量,常量,类型,函数等)时,该标识符必须是对外可见的(public)。在go语言中只需要将标识符的首字母大写就可以让标识符对外可见了,这也是为什么我们使用fmt.Println()的时候,P这个字母大写的原因。
使用方式如下:
a、先定义GOPATH变量,这是Go的工作空间
可以使用go env命令查看。
我这里是windows机器,假设GOPATH=D:\go
b、定义src目录
此时需要在D:\go下面有一个src目录,手动创建。
c、接下来
D:\go\src目录下创建clac目录,并写入文件

package calc

func Sum(x int,y int) int{           // Sum首字母大写,否则其他包找不到这个函数
	return x + y
}

d、接着是main包
必须有一个main包

package main

import (
	"calc"    //这里找的就是D:\go\src\calc目录
	"fmt"
)

func main(){
	s := calc.Sum(10,20)
	fmt.Println(s)
}

包的自定义别名

import 别名 项目

13、init()初始化函数
go语言程序执行时导入包语句会自动触发内部的init()函数的调用,需要注意,init()函数没有参数,也没返回值,init()函数是自动被调用执行,不能在代码中主动调用它,比如

package calc

import (
	"fmt"
)
func init(){
	fmt.Println("这是sum函数")
}
func Sum(x int,y int) int{
	return x + y
}

main包

package main

import (
	"calc"
	"fmt"
)


func init(){
	fmt.Println("这是main函数")
}

func main(){
	s := calc.Sum(10,20)
	fmt.Println(s)
}

执行效果如下所示:

PS D:\go> .\m.exe        
这是sum函数
这是main函数
30

如下流程图所示:

还有一个初始化函数的执行顺序如下图所示:

14、文件操作
使用bufio模块

package main
import (
	"fmt"
	"os"
	"io"
	"bufio"
)

func main(){
	fileObj,err := os.Open("./e.go")
	if err != nil{
		fmt.Println("Open file failed!!!")
		return
	}
	//记得关闭文件
	defer fileObj.Close()
	//创建一个用来从文件中读内容的对象
	reader := bufio.NewReader(fileObj)
	// 循环打印每一行内容
	for{
		line,err := reader.ReadString('\n')
		// 读取到文件末尾就退出
		if err == io.EOF {
			return
		}
		if err != nil{
			fmt.Printf("read line failed")
			return
		}
		fmt.Print(line) //这里要使用print, 不要换行
	}
}

文件内容比较多,这里不再展示了

使用ioutil工具读取文件,这个工具大概每次读取512个字节

package main
import (
	"fmt"
	"io/ioutil"
)

func main(){
	ret,err := ioutil.ReadFile("./e.go")
	if err != nil{
		fmt.Println("文件读取失败!!!")
		return
	}
        //ret是字节,这里需要string转化一下
	fmt.Print(string(ret))
}

15、写文件操作得几种方式

package main
import (
	"fmt"
	"bufio"
	"os"
	"io/ioutil"
)


func writefileDemo1(){
	// 读写文件,如果没有就创建,追加文件内容
	fileObj,err := os.OpenFile("./test.txt",os.O_WRONLY|os.O_CREATE|os.O_APPEND,0644)
	if err != nil{
		fmt.Println("Open file failed,err:%v",err)
		return
	}
	fileObj.Write([]byte("Hello world\n"))
	fileObj.WriteString("You are welcome\n")
	fileObj.Close()
}

func writefileDemo2(){
	fileObj,err := os.OpenFile("./test.txt",os.O_WRONLY|os.O_CREATE|os.O_APPEND,0644)
	if err != nil{
		fmt.Println("Open file failed,err:%v",err)
		return
	}
	defer fileObj.Close()
	wr := bufio.NewWriter(fileObj)
	wr.WriteString("hello沙河")
	wr.Flush() //将缓存中得内容写入文件

}

func writefileDemo3(){
	//下面这种不能追加,需要额外的机制来解决
	str := "hello world"
	err := ioutil.WriteFile("./test.txt", []byte(str),0666)
	if err != nil{
		fmt.Println("Write file failed ,err:",err)
		return
	}
}

func main(){

	//writefileDemo1()
	//writefileDemo2()
	writefileDemo3()

	
}

补充知识点:

使用fmt.Scanln(str)从终端读取得缺点是不能遇到空格,否则只能识别第一个空格前面的字符串,如下所示:

func main(){
	var str string
	fmt.Print("请输入内容: ")
	fmt.Scanln(&str)
	fmt.Println("输入的内容是: ",str)
}

效果如下所示:

PS D:\go> .\n.exe
请输入内容: chen chao feng
输入的内容是:  chen

用下面这种方法进行更改

func main(){
	var s string
	reader := bufio.NewReader(os.Stdin)
	fmt.Println("请输入内容: ")
	s,_ = reader.ReadString('\n')
	fmt.Printf("你输入的内容是: %s\n",s)
}

效果如下所示:

PS D:\go> .\n.exe      
请输入内容: 
Hello world
你输入的内容是: Hello world

go类型转换,字节和整型的转换

//整形转换成字节
func IntToBytes(n int) []byte {
  x := int32(n)
  bytesBuffer := bytes.NewBuffer([]byte{})
  binary.Write(bytesBuffer, binary.BigEndian, x)
  return bytesBuffer.Bytes()
}
//字节转换成整形
func BytesToInt(b []byte) int {
  bytesBuffer := bytes.NewBuffer(b)
  
  var x int32
  binary.Read(bytesBuffer, binary.BigEndian, &x)
  
  return int(x)
}

16、时间的各种使用

func main(){
	now := time.Now()
	fmt.Println(now)
	fmt.Println(now.Year())
	fmt.Println(now.Month())
	fmt.Println(now.Day())
	fmt.Println(now.Hour())
	fmt.Println(now.Minute())
	fmt.Println(now.Second())
	fmt.Println("++++++++++++++++++++++++++++++++")
	//时间戳,微秒
	fmt.Println(now.Unix())
	//纳秒
	fmt.Println(now.UnixNano())
	fmt.Println("++++++++++++++++++++++++++++++++")
	
	//time.Unix()
	ret := time.Unix(1564803667, 0)
	fmt.Println(ret)
	fmt.Println(ret.Year())
	fmt.Println(ret.Day())
	fmt.Println("++++++++++++++++++++++++++++++++")

	// 明天的这个时候
	fmt.Println(now.Add(time.Hour * 24))
	fmt.Println("################################")

	//格式化时间输出。go是从诞生日这种格式来用的
	fmt.Println(now.Format("2006-01-02"))

	// 得到年月日时分秒的格式
	fmt.Println(now.Format("2006/01/02 15:04:05"))

	//将对应的格式解析成字符串类型的时间
	timeObj, err := time.Parse("2006-01-02", "2021-08-20")
	if err != nil {
		fmt.Printf("parse time failesd, err: %v\n",err)
		return
	}
	fmt.Println(timeObj)
	fmt.Println(timeObj.Unix())   //将对应的时间格式转化成其他的格式,非常好用
}

效果如下所示:

PS D:\go> .\n.exe        
2021-08-20 19:32:26.007833 +0800 CST m=+0.003088801
2021
August
20
19
32
26
++++++++++++++++++++++++++++++++
1629459146
1629459146007833000
++++++++++++++++++++++++++++++++
2019-08-03 11:41:07 +0800 CST
2019
3
++++++++++++++++++++++++++++++++
2021-08-21 19:32:26.007833 +0800 CST m=+86400.003088801
################################
2021-08-20
2021/08/20 19:32:26
2021-08-20 00:00:00 +0000 UTC
1629417600

17、获取文件的大小和文件名称

package main

import (
	"fmt"
	"os"
)

func main(){
	//打开当前文件,os.Open()多用来读取文件
	fileObj, err := os.Open("p.go")
	if err != nil{
		fmt.Printf("open file failed ,err: %v\n", err)
		return
	}
	// 1、文件对象的类型
	fmt.Printf("%T\n", fileObj)
	// 2、获取文件对象的详细信息
	fileInfo, err := fileObj.Stat()
	if err != nil{
		fmt.Printf("get file info failed, err: %v\n", err)
		return
	}
	fmt.Printf("文件大小是: %d B\n",fileInfo.Size())
	fmt.Printf("文件名是: %s\n",fileInfo.Name())
}

效果如下所示:

PS D:\go> .\p.exe      
*os.File
文件大小是: 560 B
文件名是: p.go
posted @ 2021-08-07 09:00  峰哥ge  阅读(69)  评论(0编辑  收藏  举报