简单的go

1、安装go

      https://golang.google.cn/dl/

     1、安装  我安装在了D:\Go

           添加 D:\GoWork 目录,并在目录下增加src,此目录为写代码目录

     2、配置环境变量

          

          path中添加以下内容

          

     3、重启电脑,打开 cmd  输入: go version可以查看安装的版本

     4、安装vscode ,并添加Chinese和Go两个插件 

     5、添加代码提示

         cmd中执行以下语句:

         go env -w GO111MODULE=on
         go env -w GOPROXY=https://goproxy.io,direct

         执行完后,vscode中右下角点击install all

         使用goland直接修改配置即可:

          

     5、编写helloworld

           在D:\GoWork\src目录下添加main.go文件,并写入以下代码

package main

import "fmt"

func main (){
 
	fmt.Println("hello world!")

}

         编译代码(会生成main.exe文件):go build main.go

         执行编译后的exe文件:./main.exe

2、代码

     1、变量声明

         1、package:

                      1、main包为应用程序的入口包

                      2、包名可以与其目录不同名

                      3、一个目录下的同级文件归属一个包。

         2、关键字

                 为go语言中具有含义的字,不可作为变量名使用

                       

        3、变量与常量

                 声明方式为:var 变量名 变量类型

                 需要注意的是,函数内变量一旦声明,必须使用

                1、变量声明

var name string  //默认为""
var age int   //默认为0
var isOk bool  //默认为false

//变量赋值
name = "小明"
age = 1
isOk = true

              2、多变量声明

                 当多变量声明时,第一个有值,以下的没有值,自动使用第一个的值

var (
	name string
	age int
	isOk bool
)

//以下所有的值都为1,都使用了name的值
const (
	name int = 1
	age
	isOk
)

              3、简短变量赋值 自动判断类型
               name := "aaa" 

              4、匿名变量 _ ,如果不需要该值则直接使用下划线代替,占位使用

              5、、常量

                程序运行中数据不再改变,定义之后,不能再次赋值了

                const status = 1

              6、  iota常量计数器(只能在常量中使用)

                  当iota关键字出现时,该值会被重置为0,每新增一行常量将会被计数一次

                  下方代码中三个值从上到下分别为0,1,2

const (
	name int = iota
	age
	isOk
)

     2、基本数据类型

        1、整形

                1、 整形分为两类,有符号类型(int)和无符号类型(uint),可以理解为uint8就是byte类型,uint16就是short类型,uint64就是long类型

               

               2、特殊类型

                   主要区别于放在32或者64位系统会占用的数量

              

       2、浮点数

               只支持flout32和flout64,默认flout定义都是flout64

               amount float64 = 1.3

               flout32和flout64这两个类型都不能转换

      3、布尔值

               bool,和java中的boolean一致,判断true和false

      4、string字符串

              string也是原生类型,内部实现使用的是utf-8,string只能用双引号包裹,单引号包裹的是字符

              str := "123"   普通字符串

              str := `啊啊啊`  可换行的字符串

              1、常用操作

              

                 split举例:

    str := "123"
	arr := strings.Split(str,"2")
	fmt.Println(arr)

              2、字符串分为两种类型

                1、byte类型,表示ASCII中的字符

                2、rune类型,表示一个UTF-8的字符

             3、字符串修改

                  字符串类型本身不能修改,需要先将字符串转换为rune类型,修改完字符后,再将转换为string类型才可以

	str := "白萝卜"
	str1 := []rune(str)
	str1[0] = '红' //需要是单引号 因为rune是字符
	fmt.Println(string(str1))

      3、流程控制

         1、if

	age := 19
	if(age <= 10){
		fmt.Println("小于10")
	}else if(age >10 && age <=19){
		fmt.Println("大于10并小于19")
	}else{
		fmt.Println("大于等于19")
	}

          2、for

              1、for循环

	for i := 0; i < 19; i++ {
		fmt.Println(i)
	}

              2、无限循环

    for {
		fmt.Println('i')
	}

              3、range循环 ,i是角标,v是rune类型的值

	str := "哈哈哈"
	for i,v := range str {
		fmt.Println(i,v,string(v))
	}

      4、复杂数据类型

            1、数组

                    1、声明数组长度   :arr := [3]string{"你好","你好2","你好3"}

                    2、不声明数组长度:arr := [...]string{"你好","你好2","你好3"}

                    3、多维数组:

	//一个数组包含3个子数组,子数组两个值
	arr := [3][2]string{
		[2]string{"第一个数组","第一个数组"},
		[2]string{"第二个数组","第二个数组"},
		[2]string{"第三个数组","第三个数组"},
	}

	//
	for i, v := range arr {
		for i1 := 0; i1 < len(v); i1++ {
			v1 := v[i1]
			fmt.Println(i1,v1)
		}
		fmt.Println(i,v)
	}

           2、切片(slice)

                    切片是拥有相同元素类型的可变长度的序列,是基于数组的封装,支持自动扩容

                    切片是一个引用类型,内部包含地址,长度,容量。一般用于操作集合

                   1、定义: var arr = []int{1,2,3}

                   2、判断是否为空:arr == nil

                   3、查看长度和容量:len(arr),cap(arr)

                   4、对slice进行切割:

                             1角标后的数据:arr1 = arr[1:]

                             2角标前的数据:arr1 = arr[:2]

                  5、扩容

                           给arr追加1,2,3,并重新赋值给arr:arr = append(arr,1,2,3)

                           给一个arr追加arr2里的内容,...表示拆开:

	var arr = []int{1,2,3}
	var arr2 = []int{1,2,3}
	arr = append(arr,arr2...)
	fmt.Println(arr)

                6、赋值

                         从切片a复制到切片b,需要注意,切片b长度必须大于等于切片a

	var arr = []int{1,2,3}
	arr2 := make([]int ,3,3)
	copy(arr2,arr) // 第一个参数是目的  第二个参数是源头
	fmt.Println(arr2)

                7、删除切片中的内容

                       没有删除切片的专用方法,例如要删除切片中2角标的值,需要append2之前的值和2之后的值,间接删除了2角标

	var arr = []int{10,20,30,40}
	arr = append(arr[:1],arr[2:]...) //arr[:1]内容:[10],   arr[2:]内容:[30,40]
	fmt.Println(arr)

                8、值转换为内存并转换回来

	value := "123"
	p := &value
	fmt.Println("内存地址为:",p)
	v := *p
	fmt.Println("值为:",v)

             3、map

                     1、定义key为string,value为int的map:map1 := make(map[string]int,1)

                     2、传入值:map1["aaa"] = 1

                     3、判断key是否存在:

	if ok {
		fmt.Println(value ,"存在")
	}else {
		fmt.Println(value ,"不存在")
	}

                   4、遍历:

	for key, val := range map1 {
		fmt.Println("key:",key,"value:",val)
	}

                  5、根据key删除:delete(map1,"aaa")

                  6、对map进行排序

	//加入到切片中
	var keys []int
	for k := range map1 {
		keys = append(keys, k)
	}
	//对key排序
	sort.Ints(keys)
	for _, k := range keys {
		fmt.Println("Key:", k, "Value:", map1[k])
	}

                7、切片内部是个map

    arr := make([]map[string]int,10,10) // map[string]int,10,10前面加了一个[]代表是个切片
	arr[0] = make(map[string]int,1) // 0的位置初始化一个map,否则会报错
	arr[0]["aaa"] = 1 //给切片0位置上的map赋值
	fmt.Println(arr)

                 8、map内部是个切片

	map1 := make(map[string][]int,10)
	map1["arr1"] = []int{1,2,3,4}
	map1["arr2"] = []int{5,6,7,8}
 	fmt.Println(map1)

         4、函数

                1、定义:

//简洁的写法
func sum(x int,y int) int{
	return x + y
}

//可以返回多个值的写法
func sum(x int,y int) (ret int,ret2 int){
	ret = x + y
	ret2 = x + y
	return 
}

//返回多个值
func sum(x int,y int) (int,int){
	v := x + y
	return v,v
}

                2、闭包

                    闭包是一个函数,这个函数包含了外部作用域的变量,其实就是函数在go中可以作为变量使用

func main() {
	f1(f2)
}

func f2(f func()) {
	f()
}

func f1(f func(func())) {
	f(func() {
		fmt.Println("111")
	})
}

               3、defer延迟调用

                    代码前增加defer会在代码最后再执行,以下代码f1和f2会在最后打印

	fmt.Println("start")
	defer f1()
	defer f2()
	fmt.Println("end")

                    会先返回后执行内部函数

func main() {
	fmt.Println(f1())//最后结果是6
}
func f1() (x int){
	defer func() {
		x++
		fmt.Println(x,"1")

	}()
	fmt.Println(x,"2")

	return 5
}

               4、panic 和 recover

                  panic:抛出一个严重的错误,系统直接报错,不能再往下执行,就使用panic

                  recover:尝试解决错误,让程序继续可以执行之后的函数,当前函数就不再运行了

func main() {
	f1()
	f2()
	f3()
}
func f1() {
	fmt.Println("111")
}
func f2() {
	defer func() {
		err := recover()
		fmt.Println(err,"执行了recover")
	}()
	panic("出现了一个严重的错误")

	fmt.Println("222")
}
func f3() {
	fmt.Println("333")
}

         5、fmt

                 1、print 打印

	fmt.Print() //打印
	fmt.Println() //打印+换行
	fmt.Printf("%d%T") //格式化

	var age = 17;
	fmt.Printf("%T\n", age)  //查看类型
	fmt.Printf("%v\n", age)  //查看值
	fmt.Printf("%#v\n", age) //查看值,并加上类型标识
	fmt.Printf("%b\n", age)  //查看二进制
	fmt.Printf("%d\n", age)  //查看十进制
	fmt.Printf("%o\n", age)  //查看八进制
	fmt.Printf("%x\n", age)  //查看十六进制
	var name = "123";
	fmt.Printf("%s\n", name) //查看字符串

          

               2、fmt.Scan 获取用户的输入  

	var a string
	fmt.Scan(&a) //将地址传给scan
	fmt.Println(a)

        6、自定义类型(type)

                  定义一个自己的类型,主要是为了限制类型

                 1、定义: type myInt int

        7、结构体(struct)

                   等同于java中的类

                  1、定义

type student struct {
	name string
	age int
}

                  2、使用

	var student Student
	student.name = "名字"
	student.age = 1
    
	student := &Student{
		"a",
		1,
	}

	student2 := &Student{
		name:"a",
		age:1,
	}

         8、方法和接收者 

                    方法是作用于特定类型的函数,不能让所有人调用

                   1、定义

func (student Student)chifan() {
	fmt.Println(student.name , "吃饭")
}

                  2、调用

	var student Student
	student.name = "小黄"
	student.age = 10
	student.chifan()

                  3、继承

                       在a类中添加b类,可以直接调用b类的参数以及方法,也就实现了继承的特性

func main() {
	dog := Dog{
		Animal: Animal{"小黄"},
		age: 100,
	}
	dog.move()
}

type Animal struct {
	name string
}

type Dog struct {
	Animal
	age int
}

func (a Animal)move()  {
	fmt.Println(a.name,"会动")
}

                    4、序列化和反序列化

                        转换为json:json.Marshal

                        需要注意,由于只有大写才能被其他包识别,所以类中的字段必须是首字母大写,才可以正常转换为json,如果想要转换为json的是小写,需要在字段后增加·json:"小写的字段名"

func main() {
	dog := Dog{
		Age: 100,
	}
	json,_ := json.Marshal(dog)
	fmt.Println(string(json))
}
type Dog struct {
	Age int `json:"age"`
}

                       反序列化:json.Unmarshal

	j := "{\"age\":100}"
	var dog1 Dog
	json.Unmarshal([]byte(string(j)),&dog1) //传内存地址是为了在内部修改dog1的值
	fmt.Printf("%#v",dog1)

           9、接口

                     接口用于规定实现的方法名,只要实现了这个方法名,就可以当参数使用

                     一个接口可以有多个方法名,一个类只要全部实现了该方法名,则可以理解为这个类型的变量

func main() {
	var dog Dog
	var cat Cat

	da(dog)
	da(cat)
}

//定义类
type Dog struct {}
type Cat struct {}

//定义方法,传入接口
func da(speakInterface SpeakInterface) {
	speakInterface.speak()
}

//定义类的名称 需要与接口里的名称一致
func (c Cat)speak()  { fmt.Println("猫叫") }
func (c Dog)speak()  { fmt.Println("狗叫") }

//定义接口
type SpeakInterface interface {
	speak() //只要有这个方法即可
}

             10、指针接收和值接收的区别

                             1、指针接收的接口只能接收指针类型,值接收的接口是值或者直接都可以接收。

func main() {
	dog1 := &Dog{"小狗"} //必须指针传入,如果想值传入,需要删除方法上的*
	var dogInter DogInter = dog1
	dogInter.chi2()
}

type DogInter interface {
	chi()
	chi2()
}

//添加*只能接收指针类型
func (d *Dog)chi() {
	fmt.Println("chi")
}
func (d *Dog)chi2() {
	fmt.Println("chi2")
}

                             2、指针接收将数据修改,会直接影响类本身。值接收,方法修改,不会影响类本身

func main() {
	dog1 := Dog{"小狗"} //值传入
	dog1.chi()  
	fmt.Println(dog1) //小狗
	dog1.chi2()
	fmt.Println(dog1) //chi
}

func (d Dog)chi() {
	d.name = "chi"
}
func (d *Dog)chi2() {
	d.name = "chi"
}

          11、空接口

                   任何类型都实现了空接口,作用为传参时什么都可以传入,例如fmt.Println(),就是什么都可以传

                   也可以作为slice或者map的值,可以理解为java中的Object

                   定义:interface{}

          12、package

                   包中的标识符,如果首字母小写,表示私有,如果是大写,就是公有的

                   只有main包才能编译成可执行文件

                   1、定义:package 包名

                   2、goland添加gopath才可正常引入包

                                  

         13、init方法

                      init方法是特殊的方法,在引入包的时候会自动调用,不能手动调用

                      先执行导入的包的init,再执行本类

中的init

         14、文件操作

                     io工具包执行读取文件和导出文件操作

//io工具类方式
func f3() {
	file1, err := ioutil.ReadFile("src/demo/day1/aaa.txt")
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(string(file1))

	//打印
	ioutil.WriteFile("src/demo/day1/bbb.txt",file1,os.FileMode(777))
}

//缓冲流方式
func f2() {
	fileObj, err := os.Open("src/demo/day1/aaa.txt")
	if err != nil {
		fmt.Println(err, fileObj)
		return
	}

	reader := bufio.NewReader(fileObj)

	for {
		line, err := reader.ReadString('\n')
		if err != nil {
			return
		}
		fmt.Print(line)
	}

	fileObj.Close()
}

//os方式
func f1() {
	fileObj, err := os.OpenFile("src/demo/day1/aaa.txt",os.O_APPEND | os.O_CREATE,0644)
	if err != nil {
		fmt.Println(err, fileObj)
		return
	}

	//读文件
	var tmp = make([]byte, 128)
	for {
		//将文件中的内容读取到tmp中,返回读了多少个字节
		n, err := fileObj.Read(tmp[:])
		if err != nil {
			fmt.Println(err, fileObj)
			return
		}
		fmt.Println(string(tmp[:n]))
		if n < 128 {
			return
		}
	}

	//关闭流
	defer fileObj.Close()
}

                      

         15、反射

                       1、获取变量的类型:reflect.TypeOf(a)

func main() {
	var student student
	v := reflect.TypeOf(student)
	fmt.Println("名字:",v.Name()) //名字
	//获取字段名
	for i := 0; i < v.NumField(); i++ {
		field := v.Field(i)
		fmt.Println("字段名:",field.Name,"字段类型:",field.Type,"获取标签:",field.Tag.Get("hahaha"))
	}
}

type student struct {
	name string `json:"Name" hahaha:"哈哈哈"`
}

         16、strconv类型转换

                     将string转换为int,float,bool类型使用

	//字符串转换为数字类型  10进制   64位的
	a := "111"
	parseInt, err := strconv.ParseInt(a, 10, 64)
	//strconv.ParseBool() 转换为
	//strconv.ParseFloat()
	if err != nil {
		return
	}
	fmt.Println(parseInt)

	//数字类型转换为字符串
	b := 123
	str := fmt.Sprint(b)
	fmt.Printf("%#v",str)

      5、并发编程

             1、goroutine(个肉体)

                      只需要在调用函数的前面加一个go关键字,就是创建了一个goroutine.main函数本身就是一个goroutine。会根据main函数的终止而终止

func main() {
	for i := 0; i < 100; i++ {
		go f1(i)
	}

	fmt.Println("go ")
	time.Sleep(time.Second)//等待f1函数结束
}

func f1(i int) {
	fmt.Println("你好",i)
}

                      1、等待所有的goroutine全部关闭,再往下执行

//添加goroutine到wg中,等待wg计数器为0,再往下执行
var wg sync.WaitGroup

func main() {
	for i := 0; i < 100; i++ {
		//计数
		wg.Add(1)
		go f1(i)
	}
	//等待
	wg.Wait()
	fmt.Println("go ")
}

func f1(i int) {
	fmt.Println("你好",i)

	//关闭
	defer wg.Done()
}

            2、channel 

                    可以在多个goroutine之间传递数据

                    1、定义:a := make(chan int)

                    2、发送值:a <- 1

                    3、接收值:x := <- a

                    4、关闭通道:close()

	//创建一个有16缓存区的通道
	a := make(chan int,16)

	wg.Add(1)
	go func() {
		//从管道中获取数据
		x  := <- a
		fmt.Println("f1接收到了",x)

		defer wg.Done()
	}()

	//将数据放到管道中
	time.Sleep(10000)
	a <- 10
	fmt.Println("通道里放了一个10",a)

	wg.Wait()
	close(a)

                3、sync

                         加锁,保证线程同步

                          1、互斥锁 :var lock sync.Mutex

var lock sync.Mutex

func add() {
	lock.Lock()
	for i := 0; i < 100000; i++ {
		a = a + 1
	}
	wg.Done()
	lock.Unlock()
}

                        2、读写互斥锁:var rwLock sync.RWMutex

                        3、只执行一次的代码:sync.Once

                        4、并发安全的map:sync.Map,如果只用map大于20个同时存入,会出现并发安全的问题

                               store:设置值

                                load:取值

                         5、atomic原子类,安全的添加

                              atomic.AddInt32()

         6、网络编程

               1、tcp开发

                             接收端

func main() {
	//本地端口启动
	listen, err := net.Listen("tcp","127.0.0.1:8888")
	if err != nil {
		fmt.Println("启动失败",err)
		return
	}
	fmt.Println("启动接收")

	for{
		conn, err := listen.Accept()
		if err != nil {
			fmt.Println("接收失败",err)
			return
		}

		var tmp [128]byte
		n, err := conn.Read(tmp[:])
		if err != nil {
			fmt.Println("read失败",err)
			return
		}

		fmt.Println(string(tmp[:n]))
	}
}

                        发送端

func main() {
	//建立链接
	conn, err := net.Dial("tcp", "127.0.0.1:8888")
	if err != nil {
		fmt.Println("建立失败",err)
		return
	}

	conn.Write([]byte("发送成功啦哈"))
	conn.Close()
}

               2、http

                         启动服务

func f1(response http.ResponseWriter,request *http.Request)  {
	a := "你好"
	response.Write([]byte(a))
}

func main() {
	//启动的地址
	http.HandleFunc("/aaa",f1)
	//启动的ip
	http.ListenAndServe("127.0.0.1:8080",nil)
}

                         获取服务器的数据

	resp, err := http.Get("http://127.0.0.1:8080/aaa")
	if err != nil {
		return
	}

	all, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	}

	fmt.Println(string(all))

             3、单元测试

                       文件名必须以_test.go为结束

                       1、Test开头为测试函数,参数为T *testing.T

func TestSplit(t *testing.T) {
	ret := Split("123,aaa,bbb")
	want := []string{"123","aaa","bbb"}
	if reflect.DeepEqual(ret,want)  {
		t.Errorf("ret:%v;want:%v",ret,want)
	}
}

func Split(str string) []string {
	split := strings.Split(str, ",")
	return split
}

             4、连接mysql

                      1、下载依赖  :go get github.com/Go-SQL-Driver/MySQL

                      2、数据库连接以及增删改查

import (
	"database/sql"
	"fmt"
	_ "github.com/Go-SQL-Driver/MySQL"//需要空导入
)

var db *sql.DB

func init()  {
	initDb()
}

func main() {
	insert()
}

func insert() {
	tx, err := db.Begin() //开启事务
	if err != nil {
		fmt.Println("开启事务失败")
		return
	}
	sqlStr := "insert into course(name) values (?)"

	p, err := db.Prepare(sqlStr)
	if err != nil {
		tx.Rollback()
		fmt.Println("格式化失败")
		return
	}

	defer p.Close()

	_, execErr := p.Exec("111")
	if execErr != nil {
		tx.Rollback()
		fmt.Println("執行sql失败")
		return
	}

	tx.Commit()

}

func getById(id int) (Course){
	var cource Course

	sqlStr := "select * from course where id = ?"
	rowObj := db.QueryRow(sqlStr, id)
	//执行返回数据
	rowObj.Scan(&cource.ID,&cource.NAME)

	return cource
}

func getAll() ([]Course){

	courseList := []Course{}

	sqlStr := "select * from course"
	rows, err := db.Query(sqlStr)
	if err != nil {
		fmt.Println("查询失败")
		return courseList
	}

	for rows.Next(){
		var cource Course
		rows.Scan(&cource.ID,&cource.NAME)
		courseList = append(courseList,cource)
	}

	defer rows.Close()

	return courseList
}

type Course struct {
	ID int
	NAME string
}

//初始化db
func initDb() (err error) {
	//链接数据库
	dsn := "root:1234@tcp(127.0.0.1:3306)/book"

	db, err = sql.Open("mysql", dsn)
	if err != nil {
		fmt.Println("链接失败",err,db)
		return
	}
	pingErr := db.Ping()
	if pingErr != nil {
		fmt.Println("链接失败",pingErr,db)
		return
	}
	fmt.Println("链接数据库成功")

	return nil
}

遇到问题

 1、如果出现找不到的包,直接网上找到下载到对应文件下即可

 2、使用go mod vendor 下载包到当前

 3、先在go.mod中添加包其他地方才可使用

require (
	github.com/ylywyn/jpush-api-go-client latest
)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值