目录
学习golang注意点:
- 导的包必须使用;或者使用
_
未使用的包,作用是调用该包下的初始化方法。- 局部变量声明必须使用。
- go语言的包和java的相似,
包名.变量
访问
1. 初识go语言
1.1 Hello World
package mainimport "fmt"func main() { fmt.Println("hello world");}
1.2 go 数据类型
布尔:
var a bool = truevar b bool = false
整型:
整型分为有符号和无符号的类型
8, 16 ,32 分别代表位数
int
: 根据系统决定是32位还64位
int8
: 1个字节,-128~127 相当于java中的short;
int16
: 2个字节,-215 ~ 215 -1
int32
: 4个字节 -231 ~231 - 1
int64
: 8个字节-263 ~263 - 1
uint : .....
无符号整形都是取值0~216 - 1
var a int = -3var b uint = 3 //uint类型不可以为负数
浮点型:
var a float32 = 100.0var b float64 = 100.00 //默认
字符类型
golang中的字符使用的是字节保存的,本质就是一个int32类型
var a byte = 'a'var b byte = 'c'fmt.Print(a, "===", b) //输出的是该字节对应的字节码: 97===99fmt.Printf("%c === %c", a, b) // a === c
字符串型:
var str string = "hello world"//多行字符串,不需要使用+来连接多行var str2 string = `a asda asdasdadsadasd `
复数类型:
complex64
是两个float32组成 complex128
两个float64组成
var a complex64 = 10 + 3ivar b complex128= 10 + 3i //默认
相关操作
var v= complex(2 , 3) //构造1个复数, a := real(v) //返回复数实部 2b := image(v) 返回复数虚部 3
rune类型:
// rune is an alias for int32 and is equivalent to int32 in all ways. It is// used, by convention, to distinguish character values from integer values.//int32的别名,几乎在所有方面等同于int32//它用来区分字符值和整数值type rune = int32
1.3 变量常量
局部变量:
属于函数或者方法;声明之后必须使用
var a = 3;var b int = 3;c := 3
全局变量
b := 10
这种全局变量声明是错误的
全局变量的概念:隶属于包
,声明之后可以不使用
var a intvar ( c int d string)var e = 3
常量
局部
const a = 3
全局
const a int = 10const b = 20const ( d int = 10 e string = "ss" f = 30)
1.5 字符串相关操作
golang中string底层是通过byte数组实现的,byte使用utf-8编码标识的Unicode文本,每个汉字占3个字节
- 求长度
func strDemo() { fmt.Println(len("hello")) //5 fmt.Println(len("中")) //3 fmt.Println(len([]rune("中"))) //1, 正确获取中文字符串长度}
- 字符串遍历
//对中文无法支持func strEach() { str := "hello world" for i := 0; i < len(str); i ++ { //fmt.Print(str[i] ,"\t") // 104 101 108 108 111 32 119 111 114 108 100 //讲字节编码转为字符串输出 fmt.Printf("%c\t", str[i]) //h e l l o w o r l d }}
func strEach() { str := "hello world 中国" for i, s := range str { //0 h1 e2 l3 l4 o5 6 w7 o8 r9 l10 d11 12 中15 国 fmt.Print(i, "\t", string(s)) }}//这个可以正确的输出索引func strEachRune() { str := "中国人民" for i, s := range []rune(str) { fmt.Println(i, string(s)) }}
- 其他操作
str := "中国人民, hello world"index := strings.Index(str, "国") //存在则 index > -1, 否则 == -1 此时index=-3split := strings.Split(str, ",")replace := strings.Replace(str, "o", "2", 1) //第三个参数标识替换几个,小于0,则替换所有result := strings.EqualFold("中国", "中国2") //不区分大小写fmt.Println("中国" == "中国H") //区分大小写, 同strings.Compare()5
1.6 相互转换
1.6.1 基本数据
golang基本数据数据之间的转换可使用公:T(i)
进行相互转换
//数据之间的相互转换func transfer() { // var i int = 10 var j float64 = 11.30 x := float64(i) y := int(j) fmt.Print(x, "\t", y) //10 11}
1.6.2 string <=> 基本数据类型
- 基本类型=>string
fmt.Sprintf(format string, param interface{})
func stringTrans() { var i int = 10 var flag bool = true int_str := fmt.Sprintf("%d", i) bool_str := fmt.Sprintf("%t", flag) fmt.Println(int_str) fmt.Println(bool_str)}
strconv
func stringStrco() { var i int = 10000 var flag bool = true var price float64 = 130.32 formatInt := strconv.FormatInt(int64(i), 10) //等价: strconv.Itoa(i) formatBool := strconv.FormatBool(flag) formatFloat := strconv.FormatFloat(price, 'f', 10, 64) fmt.Println(formatInt) fmt.Println(formatBool) fmt.Println(formatFloat)}
- String=>基本数据类型
func strToBase() { str_flag := "true" str_age := "20" str_price := "20.33" flag, _ := strconv.ParseBool(str_flag) age, _ := strconv.ParseInt(str_age, 10, 64) age_int, _ := strconv.Atoi(str_age) price, _ := strconv.ParseFloat(str_price, 64) fmt.Println(flag) fmt.Println(age) fmt.Println(price) fmt.Println(age_int)}
1.6.3 字节数组和字符串
func byteAndStr() { str := "hello world, 中国" data := []byte(str) s := string(data) fmt.Println(s) fmt.Println(data)}
1.7 时间
- 获取时间
func timeOperate() { cur := time.Now() curT := time.Now().Unix() //获取时间戳 fmt.Println(cur) //2019-01-30 20:40:16.410689 +0800 CST m=+0.000353772 fmt.Println(curT) //1548852137}
- 时间和字符串转换
func formatTime() { format := time.Now().Format("2006-01-02 15:04:05") //时间戳转时间 var timestamp int64 = 1548852137 unix := time.Unix(timestamp, 0).Format("2006-01-02 15:04:05") //字符串转时间 formatTimeStr := "2017-04-11 13:33:37" strToTime, _ := time.Parse("2006-01-02 15:04:05", formatTimeStr) fmt.Println(format) //2019-01-30 21:00:53 fmt.Println(unix) fmt.Println(strToTime) //2017-04-11 13:33:37 +0000 UTC}
1.8 复合数据类型
数组和切片(slice)之间的区别:
数组:声明的时候必须指定长度
var arr [10]int
,值类型,但是在java里面数组是引用类型 Slice: 长度可变,不需要指定长度,引用类型
1. 数组
//数组的声明func createArray() { var books [3]string books[0] = "java" books[1] = "python" books[2] = "golang" names := [3]string{"lisi", "zhansan", "hand"} scores := [...]int{89, 59, 30, 100} //根据后面的内容决定长度 fmt.Println(books) fmt.Println(names) fmt.Println(scores)}//数组的相关操作func operateArray() { //数组长度 scores := [...]int{89, 59, 30, 100} fmt.Println(len(scores)) //数组遍历 for i := 0; i < len(scores); i++ { fmt.Print(scores[i], "\t") } fmt.Println() for index, value := range scores { fmt.Print(index, "==", value, "\t") }}
2. slice
slice是一个比较复杂的数据结构,也就相当于Java里面集合的概念,是一个可变长的数据
//最简单的一种声明方式func createSlice() { var args []int args = make([]int, 10) args[0] = 1 args[1] = 2 args[2] = 3 args[3] = 4 args[4] = 5 for index, value := range args { fmt.Println(index, value) }}
通过数组定义一个切片
len
切片长度, 表示当前切片元素的个数
cap
切片容量,表示切片可以容纳切片的个数,如果超出则报错
func createSlice2() { arrays := [...]int{1, 2, 3, 4, 5} slice := arrays[1:4] //[2 3 4] fmt.Println(len(slice)) //3 fmt.Println(cap(slice)) //4 slice[1] = 10 //这里可以解释下图 fmt.Println(arrays) //[1 2 10 4 5] fmt.Println(slice) // [2 10 4]}
这里容量为什么是4?,如图
append©函数
当append超出原来容量的时候,会扩展原来的容量为原先的两倍
//appendfunc appendFunc() { slice := make([]int, 2, 4) slice[0] = 1 slice[1] = 1 slice = append(slice, 2) slice = append(slice, 3) slice = append(slice, 4) fmt.Println(len(slice)) //5 fmt.Println(cap(slice)) //8}//copy函数的用法func copyFunc() { slice := make([]int, 2, 4) slice2 := make([]int, 2, 4) slice[0] = 1 slice[1] = 1 copy(slice2, slice) //相当于 slice2 := slice[:] fmt.Println(slice2) // [1 1]}
3. map
map 数据结构和java的HashMap类似。
//创建一个mapfunc createMap() { var product map[string]interface{} //声明 product = make(map[string]interface{}) //初始化 product["id"] = 1 product["title"] = "口红" product["price"] = 199.33 fmt.Println(product)}//遍历mapfunc mapForEach() { var product map[string]interface{} //声明 product = make(map[string]interface{}) //初始化 product["id"] = 1 product["title"] = "口红" product["price"] = 199.33 for key, value := range product { fmt.Println(key, value) }}
1.9 golang面向对象
1. 结构体
go语言中的结构体和Java中的类很相似,包含属性,方法等内容。首字母大写对其他包可见,首字母小写只是对本包可见。
指针和值类型: 指针类型的方法可以修改属性的值,值类型的不可以修改,
package mainimport "fmt"func main() { student := &Student{"zhansn", 24} fmt.Println(student.GetName())//zhansn student.SetName("lisi") fmt.Println(student.GetName()) //lisi}//对属性小写可以封装type Student struct { name string age int}//定义结构体的方法GetName和SetNamefunc (this Student) GetName() string { return this.name}//这里使用指针可以改变属性的内容func (this *Student) SetName(name string) { this.name = name}
2. 继承
在go语言中结构体和结构体没有继承,而是通过组合的方式来获取其他结构体的方法。此时的Student可以使用Person的所有属性和方法,无论是否封装。
package mainimport "fmt"func main() { student := &Student{} fmt.Println(student.GetName()) // "" student.SetName("lisi") fmt.Println(student.GetName()) //lisi}//对属性小写可以封装type Student struct { Person}type Person struct { name string age int}//定义类型的方法func (this Person) GetName() string { return this.name}//这里使用指针可以改变属性的内容func (this *Person) SetName(name string) { this.name = name}
3. 接口
golang接口中没有变量,只有方法。
对于java中的多态描述:重载和重写两种多态。但是在golang中无法对方法进行重载,因为golang是一门面向函数编程的语言。所以golang可以通过重写来实现多态,而且是接口和子类之间的重写。
package mainimport "fmt"func main() { ben := &Ben{"benchi"} ao := &Ao{"aodi"} ToString(ben) ToString(ao)}type Car interface { GetName() string SetName(name string)}func ToString(car Car) { fmt.Println(car.GetName())}type Ben struct { name string}func (ben Ben) GetName() string { return ben.name}func (ben *Ben) SetName(name string) { ben.name = name}type Ao struct { name string}func (this Ao) GetName() string { return this.name}func (this *Ao) SetName(name string) { this.name = name}
4. 类型断言
golang 类型断言和java中的instanceof
关键字相似,但是又比这个关键字高级,好用,实现方式val.(T)
func main() { var x interface{} x = 4 if y, ok := x.(int); ok { fmt.Println(y) }}
断言接口子类
package mainimport "fmt"func main() { ben := Ben{"benchi"} ao := Ao{"aodi"} ToString(ben) ToString(ao)}type Car interface { GetName() string}func ToString(car Car) { if ben, ok := car.(Ben); ok { fmt.Println(ben.GetName()) } else if ao, ok := car.(Ao); ok { fmt.Println(ao.GetName()) } else { fmt.Println("other type") }}type Ben struct { name string}func (ben Ben) GetName() string { return ben.name}type Ao struct { name string}func (this Ao) GetName() string { return this.name}
如下代码,有什么问题呢?此时我们使用指针类型是实现了接口notify
的方法,那么在SendNotify(u notify)
中我们必须使用子类的指针作为参数传递到该函数,如果我们使用值类型实现接口notify
的方法,例如func (this user) Notify()
这样既可以使用指针也可以使用值传递参数。
package mainimport "fmt"func main() { u := &user{"hello"} //此时必须传递指针参数 SendNotify(u)}type notify interface { Notify()}type user struct { name string}//指针实现接口func (this *user) Notify() { fmt.Println(this.name)}func SendNotify(u notify) { u.Notify()}
这是为什么呢?
对于一个方法method(param T)
可以接受值类型
和指针类型
的参数,method(param *T)
仅仅可以接受指针类
型的参数。
5. 闭包
java中有函数式编程,集合框架中有一个消费型函数forEach
,我们在golang中通过闭包实现该函数
package mainimport "fmt"func main() { data := []int{1,2,3,4,5} forEach(data, func(index int, value interface{}) { fmt.Println(index, value) })}func forEach(data []int, f func(int, interface{})) { for index, value := range data { f(index, value) }}
2. golang 杂项
2.0 defer
defer
会在函数或者方法结束前被调用,和Java中finally
相似
func main() { /** first hello world defer is called */ say()}func say() { fmt.Println("first") defer fmt.Println("defer is called") fmt.Println("hello world")}//由于return了,所以return后面的语句不会被执行func say2() { fmt.Println("first") return defer fmt.Println("defer is called") fmt.Println("hello world")}
defer
使用场景:错误处理,关闭资源,释放锁,后续会见到这些使用操作
2.1 错误处理
这里诉说的错误处理和Java中的异常处理一样,在java语言中错误处理一般都是try...catch…finally,而在golang语言中通过三个关键字对错误尽心处理:(defer recover) panic
- defer+recover来捕获异常
func catchError() { defer func() { err := recover() if err != nil { fmt.Println("出现异常", err) } }() a := 10 b := 0 x := a / b fmt.Println(x)}
- 自定义异常
func catchError() { //在这里捕获处理,如果不进行捕获,则程序会崩溃 defer func() { err := recover() if err != nil { fmt.Println("出现异常", err) } }() err := selfError() //向外抛出异常 panic(err)}func selfError() error { return errors.New("自定义异常")}
2.2 日志
package mainimport "log"func main() { // info:2019/02/04 16:47:25 LoggerDemo.go:6: message log.Println("message")}func init() { log.SetPrefix("info:") log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)}
func main() { log.Println("message") //Fatalln执行之后调用:os.Exit(1), 退出程序,后续程序不再执行 log.Fatalln("打印日志,程序退出") fmt.Println("还会执行吗")}
定制日志记录器
package loggerimport ( "log" "os" "io")var ( Debug *log.Logger //仅仅输出到控制台 Info *log.Logger Warning *log.Logger Error *log.Logger)const ( logFlag = log.LstdFlags | log.Lshortfile)func init() { file, error := os.OpenFile("info.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) if error != nil { panic(error) } Debug = log.New(os.Stdout, "debug:", logFlag) Info = log.New(io.MultiWriter(file, os.Stdout), "info:", logFlag) Warning = log.New(os.Stdout, "waring:", logFlag) Error = log.New(io.MultiWriter(file, os.Stderr), "error:", logFlag)}
测试
package mainimport "logger"func main() { logger.Debug.Println("debug") logger.Info.Println("create a info log") logger.Error.Println("create a errr log")}
2.3 IO流
package mainimport ( "os" "fmt" "bufio" "io" "io/ioutil")func openFile() { file, err := os.Open("info.log") if err != nil { fmt.Println("文件错误", err) } defer file.Close() reader := bufio.NewReader(file) for { str, err := reader.ReadString('\n') if err == io.EOF { //表示读取完毕 break } fmt.Print(str) }}//读取内容到内存中func openFile2() { data, err := ioutil.ReadFile("info.log") if err != nil { } fmt.Print(string(data))}func writeFile() { file, err := os.OpenFile("hello.txt", os.O_WRONLY| os.O_CREATE | os.O_APPEND, 0666) if err != nil { fmt.Println("创建文件错误") return } defer file.Close() writer := bufio.NewWriter(file) for i := 0; i < 5; i++ { writer.WriteString("写入数据:\n") } writer.Flush() //将缓冲区内容写入到文件中}//判断文件是否存在func IsExist() { _, e := os.Stat("info2.log") if e != nil { exist := os.IsNotExist(e) fmt.Println(exist) }}
2.5 json
package mainimport ( "encoding/json" "fmt" "time")type Book struct { Title string Author string Publish time.Time}//序列化mapfunc serializeMap() { student := make(map[string]interface{}) student["name"] = "闰土" student["age"] = 20 student["class"] = "大一" bytes, err := json.Marshal(student) if err != nil { fmt.Println("序列化错误") } fmt.Println(string(bytes)) //{"age":20,"class":"大一","name":"闰土"}}//序列化结构体func serializeStruct() { book := Book{"青春","itcloud", time.Now()} bytes, _ := json.Marshal(book) fmt.Println(string(bytes)) // {"Title":"青春","Author":"itcloud","Publish":"2019-02-05T11:14:51.094709+08:00"}}func deserializeMap() { var student map[string]interface{} data := `{"age":20,"class":"大一","name":"闰土"}` err := json.Unmarshal([]byte(data), &student) if err != nil {} fmt.Println(student)}func deserializeStruct() { var book Book bookStr := `{"Title":"青春","Author":"itcloud","Publish":"2019-02-05T11:14:51.094709+08:00"}` json.Unmarshal([]byte(bookStr), &book) fmt.Println(book)}
2.6 网络编程
1. TCP
客户端
package mainimport ( "bufio" "fmt" "net" "os")func main() { conn, _ := net.Dial("tcp", "127.0.0.1:8088") reader := bufio.NewReader(os.Stdin) line, _ := reader.ReadString('\n') n, _ := conn.Write([]byte(line)) fmt.Println(n)}
服务端
package mainimport ( "fmt" "net")func main() { listener, err := net.Listen("tcp", "127.0.0.1:8088") if flag := Checkout(err, "监听开启错误"); !flag { return } defer listener.Close() for { fmt.Println("等待客户端建立连接...") conn, err := listener.Accept() if flag := Checkout(err, "打开连接失败"); flag { fmt.Printf("conn= %v, ip = %v\n", conn, conn.RemoteAddr().String()) } go process(conn) }}func process (conn net.Conn) { defer conn.Close() for { buf := make([]byte, 1024) readLen, err := conn.Read(buf) if flag := Checkout(err, "读取失败"); !flag { return } fmt.Println(string(buf[:readLen])) }}func Checkout(err error, msg string) bool { if err != nil { fmt.Println(msg, err) return false } return true}
2. http
func main() { http.HandleFunc("/echo", echo) http.ListenAndServe(":8080", nil)}func echo(w http.ResponseWriter, r *http.Request) { body, err := ioutil.ReadAll(r.Body) if err != nil { w.Write([]byte("get body error")) return } strlen, err := w.Write(body) if err != nil && strlen != len(body) { w.Write([]byte("write a error")) }}
package mainimport ( "net/http" "time")//自定义handlerfunc main() { myHandler := &SelfHandle{format: time.RFC1123} http.Handle("/time", myHandler) http.ListenAndServe(":8080", nil)}type SelfHandle struct { format string}func (h *SelfHandle) ServeHTTP(w http.ResponseWriter, r *http.Request) { forTime := time.Now().Format(h.format) w.Write([]byte("time is " + forTime))}
多路复用处理器
package mainimport "net/http"//多路复用处理器func main() { mux := http.NewServeMux() mux.HandleFunc("/hello", hello) mux.HandleFunc("/world", world) server := &http.Server{Addr: ":8080", Handler: mux} server.ListenAndServe()}func hello(w http.ResponseWriter, r *http.Request) { w.Write([]byte("hello"))}func world(w http.ResponseWriter, r *http.Request) { w.Write([]byte("word"))}