基础

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 环境变量

官方推荐:

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/87560603open in new window

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)
}
Last Updated:
Contributors: 刘荣杰