基础
- golang 基础 函数
- 语法 函数
- 可变参数
- 指针
- 数组与切片
- 数组是值传递
- 切片是地址传递
- 数组取地址
- slice array
- 删除slice
- map
- 面向对象
- struct 绑定方法
- 包
- gopath 环境变量 * 执行 main* 接口
- 错误处理
golang 基础 函数
package main
import (
"bufio"
_"bufio"
"fmt"
_ "io/ioutil"
"os"
"reflect"
_"reflect"
"strconv"
_"strconv"
_"text/scanner"
)
func main() {
//const filename = "abc.txt"
////文件读取
//contents,error := ioutil.ReadFile(filename)
////if 后面可以跟多个语句 ,作用域为if里
//if error != nil{
// fmt.Println(error)
//}else{
// fmt2 := fmt.Sprintf("%s \n",contents)
// fmt.Println(fmt2)
//}
//var map1 = map[string]int{"abc":1,"b":11}
//var spli []int
//var spliString []string
//for k,v:=range map1 {
// spli = append(spli,v)
// spliString = append(spliString,k)
// var a = fmt.Sprintf("%v",k)
// fmt.Println(a)
//}
//fmt.Println(spli,spliString)
//intList := [] string {3:"as", 2:"sdf"}
//
//sort.StringsAreSorted(intList)
//fmt.Println(intList)
//var map1 interface{} = map[int]string{}
//
//map1="b"
//
//fmt.Println(map1)
//
//defer func(){ // 必须要先声明defer,否则不能捕获到panic异常
// fmt.Println(recover())
//// if err:=recover();err!=nil{
//// //fmt.Println(err) // 这里的err其实就是panic传入的内容,55
//// }
//}()
//f()
defer func() {
if err := recover();err!=nil{
fmt.Println(err,111111111)
}
}()
//printFile("abc.txt")
//str :=11111
//int 转 string
//fmt.Println(strconv.Itoa(str))
//str := grade(12)
//q, r := div(1, 3)
//fmt.Println(str)
//fmt.Println(q,r)
i ,err1:= eval2(1, 12, "/")
fmt.Println(i,err1)
}
func eval2(a,b float64 ,op string)(int1 float64 ,err1 error) {//返回数据语法
switch op {
case "+":
int1 = a+b
err1 = nil
case "-":
int1 = a-b
err1 = nil
case "/":
// The format fmt is one of
// 'b' (-ddddp±ddd, a binary exponent),
// 'e' (-d.dddde±dd, a decimal exponent),
// 'E' (-d.ddddE±dd, a decimal exponent),
// 'f' (-ddd.dddd, no exponent),
// 'g' ('e' for large exponents, 'f' otherwise), or
// 'G' ('E' for large exponents, 'f' otherwise).
//数据类型的转换
re := (strconv.FormatFloat(b,'f',-1,64))//
fmt.Println(re)
if b==0{
panic("b 不能为 %s" + strconv.FormatFloat(b,'E',-1,64))
}
int1 = a/b
err1 = nil
default:
//返回错误 类型为error
int1=0
err1= fmt.Errorf("%s 参数错误",op)//返回异常信息
}
return
}
func div(a,b int)(q,r int) {
q=a/b
r=a%b
return
}
//文件操作
func printFile(filename string) {
_,err := os.Open(filename)
if err != nil{
panic(err)
}
var i = string(345345)
fmt.Println(reflect.TypeOf(i))
re := fmt.Sprintf("%v",i)//格式化数据
err2 := os.MkdirAll("a",os.ModePerm)// os.ModePerm 0777 目录
fmt.Println(err2)
file ,err :=os.Create("a/bc1.txt")//创建文件
fmt.Println(err)
defer file.Close()
writer:= bufio.NewWriter(file)
writer.WriteString(re)
writer.Flush()
fmt.Println(fmt.Sprintf("%d",file))
scanner := bufio.NewScanner(file)
//输出文件内容的每一行
for scanner.Scan() {
fmt.Println(scanner.Text())
}
}
func converttoBin(n int ) string{
str := ""
return str
}
func grade(score int ) (str string) {//返回数据 语法
switch {
case score<0:
panic(fmt.Sprintf("wrong score %d",score))//抛出一个字符串
case score > 90:
str="A"
default:
panic(fmt.Sprintf("暂时没有这个区间"))
}
return str
}
func test(a int,b int) (int){
a = b / a
return a
}
func eval(a,b int ,op string) int {
var result int
switch op {
case "+":
result=a+b
case "-":
result = a-b
default:
panic("sdfdsf" + op )
}
return result
}
/**
数据类型转换
#string到int
int,err := strconv.Atoi(string)
#string到int64
int64, err := strconv.ParseInt(string, 10, 64)
//第二个参数为基数(2~36),
//第三个参数位大小表示期望转换的结果类型,其值可以为0, 8, 16, 32和64,
//分别对应 int, int8, int16, int32和int64
#int到string
string := strconv.Itoa(int)
//等价于
string := strconv.FormatInt(int64(int),10)
#int64到string
string := strconv.FormatInt(int64,10)
//第二个参数为基数,可选2~36
//对于无符号整形,可以使用FormatUint(i uint64, base int)
#float到string
string := strconv.FormatFloat(float32,'E',-1,32)
string := strconv.FormatFloat(float64,'E',-1,64)
// 'b' (-ddddp±ddd,二进制指数)
// 'e' (-d.dddde±dd,十进制指数)
// 'E' (-d.ddddE±dd,十进制指数)
// 'f' (-ddd.dddd,没有指数)
// 'g' ('e':大指数,'f':其它情况)
// 'G' ('E':大指数,'f':其它情况)
#string到float64
float,err := strconv.ParseFloat(string,64)
#string到float32
float,err := strconv.ParseFloat(string,32)
#int到int64
int64_ := int64(1234)
*/
语法 函数
re := apply(pow,3,4)
fmt.Println(re)
func pow(a,b int)int {
return int(math.Pow(float64(a),float64(b)))
}
func apply(op func(int,int)int , a,b int) int {
p := reflect.ValueOf(op).Pointer()// 反射
opName := runtime.FuncForPC(p).Name()//获取opname
fmt.Printf(opName,a,b)
return op(a,b)
}
可变参数
func sum(numbers ...int) (s int){
for i:=range numbers {
s+= numbers[i]
}
return
}
指针
var a int =2
var pa *int = &a
*pa = 3
fmt.Println(a,*pa)
a:=3
b := &a
*b =5
fmt.Println(*b,a)
a:=3
test(&a)
fmt.Println(a)
func test(b *int) {
*b+=10000
return
}
a :=2
b :=3
swap(&a,&b)
fmt.Println(a, b)
func swap(a,b *int) {
*b,*a = *a,*b
}
数组与切片
//[3]{3,2,1} 或者 [...]{3,2,1} 这种为数组
//[]int{6,4,5,6,4,6} 为切片
arr2 :=[3]int{3,2,1}
arr3 :=[]int{}
for k,v:=range arr2{
arr3 = append(arr3, v)
arr3 = append(arr3, k)
}
数组是值传递
切片是地址传递
func main() {
arr2 :=[]int{3,2,1}
arr3 := arr2//传地址
printArray(arr3)//传地址
fmt.Println(arr2)
fmt.Println(arr3)
}
func printArray(arr []int) {
for k,_ := range arr{
arr[k] +=100
}
}
[110 111 112 113 114 115 116 117 118 119 120]
[110 111 112 113 114 115 116 117 118 119 120]
func main() {
/*
var s []int // 同 s= []int{}
for i:=0;i<=10;i++{
s=append(s,2*i+1)
}
fmt.Println(s)
[1 3 5 7 9 11 13 15 17 19 21]
使用make才能copy
var s1= make([]int,10)
copy(s1,s)
*/
arr2 :=make([]int,0)
//初始化切片
for i:=0;i<=10;i++{
temp := i +10
arr2 = append(arr2,temp)
}
arr3 := make([]int,len(arr2))//创建一个空切片并且给定长度
copy(arr3,arr2)//复制一个切片
printArray(arr2)//传地址
fmt.Println(arr2)
fmt.Println(arr3)
}
func printArray(arr []int) {
for k,_ := range arr{
arr[k] +=100
}
}
[110 111 112 113 114 115 116 117 118 119 120]
[10 11 12 13 14 15 16 17 18 19 20]
数组取地址
func main() {
arr := [5]int{3,2,3,1}
printArray(&arr)
fmt.Println(arr)
}
func printArray(arr *[5]int) {
for k,_ := range arr{
arr[k] +=100
}
}
slice array
- slice 本身是没有数据只是对array 的view
func main() {
arr := [...]int{21,3,2,6,4}//这个还是数组
//同 arr := [5]int{21,3,2,6,4}//这个还是数组
arr2 := arr[:]//这个成了切片 但是这里依然是复制的地址
printArray(arr2)
// 同 printArray(arr[:])
fmt.Println(arr,arr2)
}
func printArray(arr []int) {
for k,_ := range arr{
arr[k] +=100
}
}
[121 103 102 106 104] [121 103 102 106 104]
- 添加元素时如果超越cap 系统会重新分配更大的底层数组
- append必须要接返回值 因为是值传递 s=append(s,val)
arr := [5]int{21,3,2,6,4}
s1 := arr[0:1]
s2:=s1[1:5]
fmt.Println((s1),(s2),cap(s2)) //cap(s2) //不能操作cap
[21] [3 2 6 4] 4
arr := [5]int{21,3,2,6,4}
s1 := arr[:]
s2:=s1[:]
s2 = append(s2, 2)
//未使用append [66 3 2 6 4] [66 3 2 6 4] [66 3 2 6 4] 5
//使用append 后 [21 3 2 6 4] [21 3 2 6 4] [66 3 2 6 4 2] 10
s2[0]=66
fmt.Println(arr,(s1),(s2),cap(s2)) //cap(s2) //不能操作cap
删除slice
var s= []int{}
for i:=0;i<=10;i++{
s=append(s,2*i+1)
}
var s1= make([]int,2)
copy(s1,s)
fmt.Println(s)
s = append(s[:1],s[2:]...)//语法
fmt.Println(s)
[1 3 5 7 9 11 13 15 17 19 21]
[1 5 7 9 11 13 15 17 19 21]
map
- //用 value, ok:= m[key] 来判断是否存在key
- delete(mapi,"55") 删除下标55
- map 是无顺的
- map 遍历 不保证遍历顺序, 如需顺序 需手动对key 排序(把所有的key 加到一个slice 里 slice 是可以排序的)
- map 使用哈希表,必须可以比较相等
- 除了 slice ,map , function的内建类型都可以作为key
- struct 类型也可以作为key 但是struct 不能包含上述内建类型
m:=map[string]string{
"name":"sdf",
}
m2 :=make(map[string]int)//定义空map //m2 ==empty map
//var m3 map[string]int m3==nil
fmt.Println(m2)
for k,v:= range m{
fmt.Println(k,v)
}
mapi := make(map[string]string)
mapi["1"]="lll"
mapi["2"]="ppp"
mapi["3"]="kk"
mapi["55"]="kk"
//判断map 值并输出
if causeName , ok :=mapi["55"];ok{
fmt.Println(causeName)
}
fmt.Println(mapi)
- []byte(s) string转换成byte
func main() {
str := lengthOfNonRepeatingSubStr("tyutyutyii")
fmt.Println(str)
}
func lengthOfNonRepeatingSubStr(s string) map[byte]int {
lastOccurred:=make(map[byte]int)
start :=0
maxlength := 0
// []byte(s) string转换成byte
for i,ch:=range []byte(s){
fmt.Println(i,ch)//ch 好像是ascii码
lastI,ok:=lastOccurred[ch]
if ok && lastI>=start{
start = lastI+1
}
if i-start+1>maxlength{
maxlength=i-start+1
}
lastOccurred[ch]=i
}
//re :=len(lastOccurred)
//
//fmt.Println(re)
return lastOccurred
}
s := "y地方"
for _,b :=range []byte(s){
fmt.Printf("%X ", b)
}
每一个中文占用的是3字节 utf8 编码
79 E5 9C B0 E6 96 B9
for i,ch:=range s{//ch is a rune(int32) unicode编码
fmt.Println(i,ch)
}
1 22320
4 26041
fmt.Println(utf8.RuneCountInString(s))
3
bytes := []byte(s)
for len(bytes)>0{
ch,size:=utf8.DecodeRune(bytes)
bytes=bytes[size:]//截取重新循环
fmt.Printf("%c ",ch)
}
y 地 方
//转换
for i,ch:= range []rune(s){
fmt.Printf("%d %c",i,ch)
}
/*
//rune 是 int32 的别名
同
for i,ch:= range []int32(s){
re :=fmt.Sprintf("%d %c",i,ch)//%c 输出整数对应的字符
fmt.Println(re)
}
*/
y 地 方 0 y1 地2 方
/*
%v 输出结构体 {10 30}
%+v 输出结构体显示字段名 {one:10 tow:30}
%#v 输出结构体源代码片段 main.Point{one:10, tow:30}
%T 输出值的类型 main.Point
%t 输出格式化布尔值 true
%d`输出标准的十进制格式化 100
%b`输出标准的二进制格式化 99 对应 1100011
%c`输出定整数的对应字符 99 对应 c
%x`输出十六进制编码 99 对应 63
%f`输出十进制格式化 99 对应 63
%e`输出科学技科学记数法表示形式 123400000.0 对应 1.234000e+08
%E`输出科学技科学记数法表示形式 123400000.0 对应 1.234000e+08
%s 进行基本的字符串输出 "\"string\"" 对应 "string"
%q 源代码中那样带有双引号的输出 "\"string\"" 对应 "\"string\""
%p 输出一个指针的值 &jgt 对应 0xc00004a090
% 后面使用数字来控制输出宽度 默认结果使用右对齐并且通过空格来填充空白部分
%2.2f 指定浮点型的输出宽度 1.2 对应 1.20
%*2.2f 指定浮点型的输出宽度对齐,使用 `-` 标志 1.2 对应 *1.20
*/
jgt := Point{10,30}
fmt.Printf("%v\n",jgt) // {10 30}
fmt.Printf("%+v\n",jgt) // {one:10 tow:30}
fmt.Printf("%#v\n",jgt) // main.Point{one:10, tow:30}
fmt.Printf("%T\n",jgt) // main.Point
fmt.Printf("%t\n",true) // true
fmt.Printf("%d\n",100) // 100
fmt.Printf("%b\n",99) // 99 对应 1100011
fmt.Printf("%c\n",99) // 99 对应 c
fmt.Printf("%x\n",99) // 99 对应 63
fmt.Printf("%f\n",99.9) // 99.9 对应 99.900000
fmt.Printf("%e\n",123400000.0) // 123400000.0 对应 1.234000e+08
fmt.Printf("%E\n",123400000.0) // 123400000.0 对应 1.234000e+08
fmt.Printf("%s\n","\"string\"") // "\"string\"" 对应 "string"
fmt.Printf("%q\n","\"string\"") // "\"string\"" 对应 "string"
fmt.Printf("%p\n",&jgt) // &jgt 对应 0xc00004a090
fmt.Printf("%6d\n",8) // &jgt 对应 0xc00004a090
fmt.Printf("%2.2f\n",1.2 ) // 1.2 对应 1.20
fmt.Printf("*%2.2f\n",1.2 ) // 1.2 对应 *1.20
// 输出格式化的字符串。`Sprintf` 则格式化并返回一个字 符串而不带任何输出。
s := fmt.Sprintf("是字符串 %s ","string")
fmt.Println(s) // 是字符串 %s 对应 是字符串 string
// 你可以使用 `Fprintf` 来格式化并输出
fmt.Fprintf(os.Stderr, "格式化 %s\n", "error")
- 使用range 遍历pos,rune对
- 使用utf8.RuneCountInString获得字符数量
- 使用len获得字节长度
- 使用[]byte获得字节
- strings.包操作字符串
Fields split join//分割字符串
contains Index //查找字串
ToLower ToUpper //
Trim TRimRight,TrimLeft
s:="d dfgdfgdfgf跑就跑看 "
s2 :=[]string{"asd","uu"}
fmt.Println(strings.ToUpper(s))//DFGDFGDFGF跑就跑看
fmt.Println(strings.Fields(s))//[dfgdfgdfgf跑就跑看]
fmt.Println(strings.Split(s,"d"))//[ fg fg fgf跑就跑看]
fmt.Println(strings.Join(s2," --"))//asd --uu
fmt.Println(strings.Contains(s,"p")) //字符串查找 false true
fmt.Println(strings.Index(s,"f")) //字符串查找 2
fmt.Println(strings.ToLower(s)) // dfgdfgdfgf跑就跑看
fmt.Println(strings.Trim(s," ")) // 去两边空格
fmt.Println(strings.TrimRight(s," ")) // 右边
fmt.Println(strings.TrimLeft(s,"d ")) // 去左边d和空格
面向对象
- go语言仅支持封装 不支持继承多态
- go语言没有class 只有struct
func main() {
var root treeNode
root = treeNode{value:3}
root.left=&treeNode{}
root.right=&treeNode{5,nil,nil}
root.right.left=new(treeNode)
fmt.Println(root)
nodes := []treeNode{
{value:3},
{},
{6,createNode(55),&root},
{6,createNode(55),&root},
}
fmt.Println(nodes)
}
//工厂
func createNode(value int)*treeNode {
return &treeNode{value:value}
}
struct 绑定方法
func main() {
var root treeNode
root = treeNode{value:3}
root.left=&treeNode{}
root.right=&treeNode{5,nil,nil}
root.right.left=new(treeNode)
fmt.Println(root)
nodes := []treeNode{
{value:3},
{},
{6,createNode(55),&root},
{6,createNode(55),&root},
}
fmt.Println(nodes)
root.setValue(555)
root.print()
}
//拷贝值
func (node treeNode)print() {
fmt.Print(node.value)
}
//拷贝地址
func (node *treeNode)setValue(value int) {
node.value=value
}
root.traverse()
遍历每一个treeNode里的value 先遍历左边的再便利右边的
func (node *treeNode)traverse() {
if node == nil{
return
}
node.print()
node.left.traverse()
node.right.traverse()
}
建议
- 改变内容必须使用指针接收者
- 结构过大也需要考虑使用指针接收者
- 一致性:如果有指针接收者就都使用指针接收
封装(包)
- 名字一般使用CamelCase
- 首字母大写:public
- 首字母小写:private
包
- 每个目录一个包
- main包包含可执行入口
- 包可以是不同文件(定义同一个包)
- 扩充系统类型或者别人的类型
type MyTreeNode struct {
node *treeNode
}
gopath 环境变量
官方推荐:
- 所有项目和第三方库放在同一个gopath
- 使用 gopm 来获取无法下载的包
- go get github.com/gpmgo/gopm
- go get -v github.com/gpmgo/gopm
demo
gopm get -g -v -u golang.org/x/tools/cmd/goimport
装到bin里
go install golang.org/x/tools/cmd/goimports
./goimports
go build src/golang.org/x/tools/cmd/goimports
执行 main
- go build 来编译
- go install 产生pkg文件和可执行文件
- go run 直接编运行
- src git repository 1(项目目录)
- pkg git repository 1(build 的过程文件)
- bin 执行文件1,2,3(编译好的可执行文件)
接口
- duck typing
type Retriever interface {
Get(url string) string
}
func download(r Retriever)string {
return r.Get("http://www.baidu.com");
}
func main() {
//实现了retriever 的get 方法
var r Retriever
r = mock.Retriever{}
fmt.Println(download(r))
}
type Retriever struct {
Contents string
}
//实现接口的get 方法
func (r Retriever)Get(url string) string {
res , err := http.Get(url)
if err !=nil{
panic(err)
}
result, err :=httputil.DumpResponse(res,true)
res.Body.Close()
if err !=nil{
panic(err)
}
return string(result)
}
- 只要实现了接口方法 就能使用
- 实现是隐式的
数据类型判断
https://blog.csdn.net/weixin_43851310/article/details/87560603
if value, ok := data.(int); ok == true {
fmt.Printf("x[%d] 类型为int,内容为%d\n",index,value)
}
for index, data := range i{
switch value := data.(type) {
case int:
fmt.Printf("x[%d] 类型为int,内容为%d\n",index,value)
case string:
fmt.Printf("x[%d] 类型为string,内容为%s\n",index,value)
case Student:
fmt.Printf("x[%d] 类型为Student,内容为name=%s,age=%d\n",index,value.name,value.age)
}
}
错误处理
defer func() {
if p := recover(); p != nil {
if _ , ok := p.(string);ok{
fmt.Println(p)
}else{
fmt.Println("程序错误",p)
}
}
}()
res , err := http.Get(url)
if err !=nil{
panic("1")
panic(err)
}
result, err :=httputil.DumpResponse(res,true)
res.Body.Close()
if err !=nil{
panic(err)
}