编译
go build xxx.go
即可编译
go build -o xxx.exe xxx.go
指定编译后的文件名
字符串类型
go的字符串是由 字节 组成的
go中的字符串一旦赋值是不能改变的
package main //当前包名
import (
"fmt"
)
func main() {
s := "sf"
s[0] = 'a' //报错 不可修改
}
反引号 让字符串保持原格式
package main //当前包名
import (
"fmt"
)
func main() {
s := `
import (
"fmt"
"unsafe"
)
`
}
基本数据类型转换
var num int = 100
var num1 float32 = float32(num)
fmt.Printf("%T %f", num1, num1)
基本数据类型和string互相转换
var num int = 100
s := fmt.Sprintf("数字转换:%d", num)
fmt.Printf("%s", s)
var s string = "100"
n, _ := strconv.Atoi(s)
fmt.Printf("转换后的数字:%d", n)
值类型和引用类型
值类型:基本类型 int string 数组 结构体 在栈中存储
引用类型:指针 silence切片map 管道interface 通常在堆中存储
switch语句
n := 1
switch n {
case 1, 2: //可以匹配多个条件
fmt.Print("值是1 或者2")
fmt.Print("结束")
//不需要写break
case 3:
fmt.Print("值是3")
fmt.Print("结束")
default:
fmt.Print("其余值")
fmt.Print("结束")
}
main函数
package main //当前包名
//导多个包格式
import (
"fmt"
"time"
)
func main() {
fmt.Printf("hello")
time.Sleep(time.Second)
}
4中声名变量的方式和多变量声名
package main //当前包名
//导多个包格式
import (
"fmt"
)
func main() {
//方式1:声名一个变量 默认的值是0
var a int
fmt.Println(a)
fmt.Printf("type of a =%T\n", a) //输出变量类型
//方式2:声名一个变量 初始化一个值
var b int = 100
fmt.Println(b)
fmt.Printf("type of b =%T\n", b)
//方式3:声名时直接赋值,根据值判断类型,不需写类型
var c = 200
fmt.Println(c)
fmt.Printf("type of c =%T\n", c)
//方式4:省去var关键字,直接自动匹配 (常用方法) 不能用于声名全局变量
d := 300
fmt.Println(d)
fmt.Printf("type of d =%T\n", d)
//声名多个变量
var e, f int = 1, 2
fmt.Println(e, f)
var g, h = 3, "dale"
fmt.Println(g, h)
var (
x int = 5
y int = 6
)
fmt.Println(x, y)
}
字符串常用函数
const实现枚举功能
package main //当前包名
import "fmt"
//枚举
const (
Arrow = iota // 开始生成枚举值, 默认为0
Shuriken
SniperRifle
Rifle
Blower
)
func main() {
fmt.Println(Arrow)
}
多返回值的3种写法
package main //当前包名
import "fmt"
//函数名 形参 形参 返回值
func add(a int, b int) int {
return a + b
}
//函数名 形参 形参 返回值 返回值(匿名)
func sub(a int, b int) (int, int) {
return a - b, 1
}
//函数名 形参 形参 返回值 返回值(返回值带名字)
func del(a int, b int) (r1 int, r2 int) {
r1 = a - b
r2 = 5
return
}
func main() {
a := add(3, 2)
fmt.Println(a)
b, c := sub(6, 3)
fmt.Println(b, c)
}
匿名导包
import(
_ "fmt"
)
匿名导入包 但是不使用包的导出函数,仅调用init方法
给包起别名
import(
mylib "fmt"
)
//使用的时候
mylib.Print("test")
匿名导入包 但是不使用包的导出函数,仅调用init方法
defer
defer相当于final,在函数的最后执行 用于清理资源
package main //当前包名
import "fmt"
func test() {
defer fmt.Println("test end1")
defer fmt.Println("test end2")
fmt.Println("test run")
}
func main() {
test()
}
执行结果 test run test end2 test end1
数组和动态数组
package main //当前包名
import "fmt"
func main() {
//固定长度数组
var arr [10]int
for i := 1; i < len(arr); i++ {
arr[i] = i
}
//第一种遍历方式
for i := 1; i < len(arr); i++ {
fmt.Println(arr[i])
}
//第二种遍历方式
for index, value := range arr {
fmt.Println(index, value)
}
}
package main //当前包名
import "fmt"
//动态数组传参
func print(arr []int) {
//如果某一个返回值不使用,可以用_来表示匿名
for _, value := range arr {
fmt.Println(value)
}
//切片是引用传递 修改值会影响原始值
arr[0] = 100
}
func main() {
//动态数组 slice:切片
arr := []int{1, 2, 3, 4}
print(arr)
//会输出100
fmt.Println(arr[0])
}
slice切片的4种声名和定义方式
package main //当前包名
import "fmt"
func main() {
//切片第1种方式:直接给定大小
sli1 := []int{1, 2, 3, 4}
fmt.Println(sli1[0])
//第2种 申明sli2是一个切片,但是没有分配空间 使用make来开辟空间
var sli2 []int
sli2 = make([]int, 3)
sli2[0] = 100
fmt.Println(sli2[0])
//第3种 申明sli2是一个切片并且使用make来开辟空间
var sli3 []int = make([]int, 3)
sli3[0] = 100
fmt.Println(sli3[0])
//第4种 使用类型推导
sli4 := make([]int, 3)
sli4[0] = 100
fmt.Println(sli4[0])
arr1 := [...]int{1, 2, 3} //定义数组 类型 [3]int
arr2 := arr1[:] //arr2 是切片类型 []int
fmt.Printf("%T\n", arr2)
}
判断切片是否为空
sli1 := []int{1, 2, 3, 4}
fmt.Println(sli1[0])
if sli1 == nil {
fmt.Println("slice是空的")
}
切片的追加和截取
package main //当前包名
import "fmt"
func main() {
//sli1 len 是3 ,cap(容量) 是5
sli1 := make([]int, 3, 5)
sli1[0] = 0
sli1[1] = 1
sli1[2] = 2
sli1 = append(sli1, 6) //追加一个元素6 len变成4 cap 还是5
//如果append后len大于cap,那么切片的容量就会再次增加一个cap的大小
//切片的截取 从第0个元素开始截取,取的大小是2个.取出的元素是第0和第1个
//这种情况是浅拷贝,修改sli2元素的值,sli1里面的也会改变
sli2 := sli1[0:2]
fmt.Println(sli2)
//深拷贝
sli3 := make([]int, 3)
copy(sli3, sli1)
fmt.Println(sli3)
}
map的3中声名和定义方式
package main //当前包名
import "fmt"
func main() {
//方式1
var myMap1 map[string]string
if myMap1 == nil {
fmt.Println("map是空的")
}
//在使用map前.需要先用make给map分配数据空间
myMap1 = make(map[string]string, 10)
myMap1["1"] = "java"
myMap1["2"] = "c++"
fmt.Println(myMap1)
//方式2
myMap2 := make(map[int]string)
myMap2[1] = "go"
myMap2[2] = "delphi"
fmt.Println(myMap2)
//方式3
myMap3 := map[string]string{
"1": "php",
"2": "python",
}
fmt.Println(myMap3)
}
map的增删改查
package main //当前包名
import "fmt"
func main() {
var myMap1 map[string]string
//在使用map前.需要先用make给map分配数据空间
myMap1 = make(map[string]string, 10)
myMap1["1"] = "java"
myMap1["2"] = "c++"
//添加
myMap1["3"] = "go"
//删除
delete(myMap1, "1")
//修改
myMap1["2"] = "c"
//遍历
for key, value := range myMap1 {
fmt.Println(key, value)
}
}
map切片
map会自动扩容 map的切片不行 需要使用append
a := make([]map[int]string, 2) //分配map切片
b := map[int]string{1: "djaigen"} //一个map对象
a[0] = b //map切片中添加一个map对象
struct的4种声明方式
package main
import (
"fmt"
)
type Person struct {
Name string
Age int
}
func main() {
var Per1 Person
Per1.Age = 20
var Per2 Person = Person{"dale", 30}
Per2.Age = 20
Per3 := &Person{"dale", 30}
Per3.Age = 20
Per4 := new(Person)
Per4.Age = 20
fmt.Println(Per4)
}
new 一个struct
package main //当前包名
import "fmt"
var (
app = NewApp()
)
func NewApp() *App {
app := new(App)
app.auth = "dale"
app.title = "happy"
return app
}
type App struct {
title string
auth string
}
func main() {
//%v 可以打印任何结构
fmt.Printf("%v\n", *app) //这里使用了解指针
}
类
类的封装
package main //当前包名
import "fmt"
type Hero struct {
//如果类的属性首字母大写,代表外部可以访问.小写属性只能在类的内部使用
Name string
Level int
}
//给结构体绑定方法
func (hero *Hero) GetName(Name string) string {
return hero.Name
}
func (hero *Hero) SetName(Name string) {
hero.Name = Name
}
func (hero *Hero) Show() {
fmt.Println(hero.Name, hero.Level)
}
func main() {
dale := Hero{"dale", 100}
dale.Show()
dale.SetName("daying")
dale.Show()
}
继承
package main //当前包名
import "fmt"
type Human struct {
//如果类的属性首字母大写,代表外部可以访问.小写属性只能在类的内部使用
Name string
sex string
}
//给结构体绑定方法
func (human *Human) Eat() {
fmt.Println("eat")
}
type SuperMan struct {
Human //SuperMan 继承Human类的方法
level int
}
func main() {
dale := SuperMan{Human{"dale", "female"}, 100}
dale.Eat()
}
多态
package main //当前包名
import "fmt"
//本质是一个指针
type AnimalIF interface {
GetName()
}
type Cat struct {
}
//给结构体绑定方法
func (cat *Cat) GetName() {
fmt.Println("cat")
}
type Dog struct {
}
//给结构体绑定方法
func (dog *Dog) GetName() {
fmt.Println("dog")
}
func main() {
var animal AnimalIF //接口的数据类型,父类指针
animal = &Cat{}
animal.GetName()
animal = &Dog{}
animal.GetName()
}
万能数据类型 类型断言
package main //当前包名
import "fmt"
//万能数据类型 相当于void *
func Test(arg interface{}) {
value, ok := arg.(string) //类型断言 如果是string会转换成功 如果失败 ok是false
if !ok {
fmt.Println("不是字符串类型")
} else {
fmt.Println("字符串类型", value)
}
}
func main() {
Test(111)
Test("hello")
}
反射
package main //当前包名
import (
"fmt"
"reflect"
)
// 万能数据类型 相当于void *
func Test(arg interface{}) {
fmt.Println(reflect.TypeOf(arg), reflect.ValueOf(arg))
}
func main() {
Test(111)
Test("hello")
}
转json
package main //当前包名
import (
"encoding/json"
"fmt"
)
// 可以给字段定义标签
type resume struct {
Name string `json:"name"`
Sex string `json:"sex"`
}
func main() {
a := resume{"dale", "female"}
jsonstr, err := json.Marshal(a)
if err == nil {
fmt.Printf("%s", jsonstr)
}
}
互斥锁
package main //当前包名
import (
"fmt"
"sync"
"time"
)
var (
Sum int
lock sync.Mutex
)
func test() {
lock.Lock()
Sum = Sum + 1
lock.Unlock()
}
func main() {
for i := 0; i < 50000; i++ {
go test()
}
time.Sleep(time.Second * 2)
fmt.Println(Sum)
}
channel
package main //当前包名
import (
"fmt"
"time"
)
func main() {
//定义一个channel 类型是int 无缓冲,chan两边的代码无论谁先运行到chan这里都需要等待
c := make(chan int)
//c := make(chan int,3) 带缓冲的channel
go func() {
time.Sleep(time.Second)
c <- 100 //把值写入到管道
close(c) //关闭channel
}() //最后这个() 代表调用这个匿名函数
num := <-c //从管道读取数据 阻塞
fmt.Println(num)
}
channel与range
package main //当前包名
import (
"fmt"
)
func main() {
//定义一个channel 类型是int 无缓冲,chan两边的代码无论谁先运行到chan这里都需要等待
c := make(chan int)
//c := make(chan int,3) 带缓冲的channel
go func() {
for i := 0; i < 5; i++ {
c <- i
}
close(c) //关闭channel
}() //最后这个() 代表调用这个匿名函数
//for 无限循环
// for {
// if data, ok := <-c; ok {
// fmt.Println(data) //成功读到数据 就输出数据
// } else {
// break //channel关闭了就退出
// }
// }
//也可以用range来接收
for data := range c {
fmt.Println(data) //成功读到数据 就输出数据
}
fmt.Println("channel已关闭")
}
channel实现等待
package main //当前包名
import (
"fmt"
)
func readData(a chan int, b chan int) {
for {
if data, ok := <-a; ok {
fmt.Printf("读取到的数据%d\n", data)
} else {
fmt.Printf("管道关闭\n")
//读取完了 通知关闭管道了
close(b)
break
}
}
}
func writeData(a chan int) {
for i := 0; i < 10; i++ {
a <- i
}
close(a)
}
func main() {
a := make(chan int, 10)
b := make(chan int, 1)
go readData(a, b)
go writeData(a)
//等待数据读取完 然后退出
if data, ok := <-b; ok {
fmt.Printf("读取到的数据%d\n", data)
} else {
fmt.Printf("关闭了\n")
}
}
ubuntu安装golang apt-get install golang
go设置开启gomodules go env -w GO111MODULE=on
go设置国内代理 go env -w GOPROXY=https://goproxy.cn,direct
调用自己本地写的包
先在项目根目录初始化gomodule go mod init github.com/9GProxy
github.com/9GProxy是自己随便起的名字
然后项目下有一个server目录,里面有一个server.go 包名server
在main包中调用自己写的包