您的位置 首页 golang

golang基础

变量

 // 声明格式  
var 变量名 变量类型 
var xxx string 

a := fujingjie  :=就是简略写法

_ 下划线就是匿名变量
  

常量和iota

 用const定义,定义的时候必须赋值
  
 iota是常量计数器,只能在常量表达式里用
const (
        n1 = iota //0
        n2        //1
        n3        //2
        n4        //3
    )
  

if else

 if 表达式1 {
    分支1
} else if 表达式2 {
    分支2
} else{
    分支3
}
  

for

 for 初始语句;条件表达式;结束语句{
    循环体语句
}

func forDemo() {
    for i := 0; i < 10; i++ {
        fmt.Println(i)
    }
}
// 初始语句和结束语句可以省略,类似while,省略初始语句;还得写

// for range遍历数组、切片、字符串、map 及通道(channel)
  

switch

 s := "a"
switch {
case s == "a":
    fmt.Println("a")
    fallthrough
case s == "b":
    fmt.Println("b")
case s == "c":
    fmt.Println("c")
default:
    fmt.Println("...")
}

// switch只能有一个default
// fallthrough执行满足条件的case的下一个case
  

goto

 func gotoDemo2() {
    for i := 0; i < 10; i++ {
        for j := 0; j < 10; j++ {
            if j == 2 {
                // 设置退出标签
                goto breakTag 
            }
            fmt.Printf("%v-%v\n", i, j)
        }
    }
    return
    // 标签
breakTag:
    fmt.Println("结束for循环")
}

// goto 跳到指定位置
  

break

 func breakDemo1() {
BREAKDEMO1:
    for i := 0; i < 10; i++ {
        for j := 0; j < 10; j++ {
            if j == 2 {
                break BREAKDEMO1
            }
            fmt.Printf("%v-%v\n", i, j)
        }
    }
    fmt.Println("...")
}
// break 跳出循环
  

continue

 func continueDemo() {
forloop1:
    for i := 0; i < 5; i++ {
        // forloop2:
        for j := 0; j < 5; j++ {
            if i == 2 && j == 2 {
                continue forloop1
            }
            fmt.Printf("%v-%v\n", i, j)
        }
    }
}
// continue 继续下一次循环 只能在for循环中使用
  

数组

 var 数组变量名 [元素数量]T

a := [...]int{1, 3}  // 可以用... 来让编译器自行推导

// 二维数组
// 多维数组只有第一层可以使用...来让编译器推导数组长度
a := [3][2]string{
        {"北京", "上海"},
        {"广州", "深圳"},
        {"成都", "重庆"},
    }
  

切片

 var name []T

// 切片的本质就是对底层数组的封装,它包含了三个信息:底层数组的指针、切片的长度(len)和切片的容量(cap)

// 要检查切片是否为空,请始终使用len(s) == 0来判断,而不应该使用s == nil来判断

// append方法,为切片添加元素
s := []int{}  // 没有必要初始化
s = append(s, 1, 2, 3)

// 删除切片
// 切片a中删除索引为index的元素,操作方法是a = append(a[:index], a[index+1:]...)

func main() {
    // 从切片中删除元素
    a := []int{30, 31, 32, 33, 34, 35, 36, 37}
    // 要删除索引为2的元素
    a = append(a[:2], a[3:]...)
    fmt.Println(a) //[30 31 33 34 35 36 37]
}
  

map

 map[KeyType]ValueType

// map默认值为nil,要用make来分配
make(map[KeyType]ValueType, [cap])

// delete从map删除键值队
delete(map, key)
  

函数

 func 函数名(参数)(返回值){
    函数体
}
  

defer

 // 先被defer的语句最后被执行,最后被defer的语句,最先被执行
func main() {
    fmt.Println("start")
    defer fmt.Println(1)
    defer fmt.Println(2)
    defer fmt.Println(3)
    fmt.Println("end")
}
  

panic和recover

 // 类似python中的try except

func funcA() {
    fmt.Println("func A")
}

func funcB() {
    // defer在最后执行,下面先触发了panic,最后执行的defer
    defer func() {  
        err := recover()
        //如果程序出出现了panic错误,可以通过recover恢复过来
        if err != nil {
            fmt.Println("recover in B")
        }
    }()
    panic("panic in B")
}

func funcC() {
    fmt.Println("func C")
}
func main() {
    funcA()
    funcB()
    funcC()
}
  

指针

可以理解为就是内存地址

  • 函数是值拷贝操作,所以要修改值就需要用到指针操作
  • 对变量进行取地址(&)操作,可以获得这个变量的指针变量。
  • 指针变量的值是指针地址。
  • 对指针变量进行取值(*)操作,可以获得指针变量指向的原变量的值。
 func modify1(x int) {
   x = 100
}

func modify2(x *int) {
   *x = 100
}

func main() {
   a := 10
   modify1(a)
   fmt.Println(a) // 10
   modify2(&a)
   fmt.Println(a) // 100
}
  
  • new和make用来做内存分配的,因为Go语言中对于引用类型的变量,我们在使用的时候不仅要声明它,还要为它分配内存空间,否则我们的值就没办法存储,就会出发panic,所以要用new和make来做内存分配。
  • 二者都是用来做内存分配的。
  • make只用于slice、map以及channel的初始化,返回的还是这三个引用类型本身;
  • 而new用于类型的内存分配,并且内存对应的值为类型零值,返回的是指向类型的指针。
  • new返回的是一个指向该类型内存地址的指针,比如int就返回*int
  • make返回类型本身
 func main() {

   var a *int
   a = new(int)
   *a = 100
   fmt.Println(*a)

   var b map[string]int
   b = make(map[string]int, 10)
   b["xxx"] = 100
   fmt.Println(b)
}
  

结构体

结构体有点类似python中的类

 package main

import (
    "fmt"
    "os"
)


func main()  {
    sm := NewStudentMan()
    for {
        ShowMenu()
        var input int
        fmt.Println("choose number")
        fmt.Scanf("%d /n", &input)
        switch input {
        case 1:
            stu := getInput()
            sm.addStudent(stu)
        case 2:
            stu := getInput()
            sm.modifyStudent(stu)
        case 3:
            sm.showStudentList()
        case 4:
            os.Exit(0)
        }
    }
}

// 获取用户的输入信息
func getInput()  *Student{
    var (
        id int
        name string
        age int
        score int
    )
    fmt.Println("please input student message")
    fmt.Println("please enter id")
    fmt.Scanf("%d \n", &id)
    fmt.Println("please enter name")
    fmt.Scanf("%s \n", &name)
    fmt.Println("please enter age")
    fmt.Scanf("%d \n", &age)
    fmt.Println("please enter score")
    fmt.Scanf("%d \n", &score)

    stu := NewStudent(id, age, score, name)
    return stu

}

// ShowMenu 展示菜单
func ShowMenu() {
    fmt.Println("WelCome")
    fmt.Println("Press 1 add student")
    fmt.Println("Press 2 modify student")
    fmt.Println("Press 3 show all student")
    fmt.Println("Press 4 exit")
}

// Student 定义学生的结构体,结构体类似python中的类
type Student struct {
    id int
    name string
    age int
    score int
}

// NewStudent 定义Student的构造函数,构造函数就是类似python类中的__init__函数,用指针是因为struct是值类型,所以值拷贝的开销会比较大
func NewStudent(id,age,score int, name string) *Student{
    return &Student{
        id: id,
        name: name,
        age: age,
        score: score,
    }
}

// StudentMan 定义StudentMan的结构体,allStudents是一个 Student的指针切片
type StudentMan struct {
    allStudents []*Student
}

// NewStudentMan StudentMan的构造函数,allStudents是一个切片,所以需要用make来初始化分配内存空间
func NewStudentMan() *StudentMan{
    return &StudentMan{
        allStudents: make([]*Student,0,50 ),
    }
}

// 定义一个新增学生的方法,就是给StudentMan构造函数增加一个方法  go中的方法是一种叫做接收者的函数,类似python中的self,下面的s就是类似于self
func (s *StudentMan)addStudent(NewStu *Student) {
    s.allStudents = append(s.allStudents, NewStu)
}

func (s *StudentMan)modifyStudent(NewStu *Student) {
    for i, v :=range s.allStudents{
        if NewStu.id == v.id{
            s.allStudents[i] = NewStu
            return
        }
    }
    fmt.Println("未找到该学生")
}

func (s *StudentMan)showStudentList() {
     for _, value := range s.allStudents{
        fmt.Printf("学号: %d \n", value.id)
        fmt.Printf("姓名: %s \n", value.name)
        fmt.Printf("年龄: %d \n", value.age)
        fmt.Printf("分数: %d \n", value.score)
     }
}
  

接口

  • 定义
 type 接口类型名 interface{
    方法名1( 参数列表1 ) 返回值列表1
    方法名2( 参数列表2 ) 返回值列表2
    …
}
  
  • 接口用法,面向接口编程
 package main

import "fmt"

// 定义支付宝的struct
type ZhiFuBao struct {
    // 支付宝
}

// Pay 支付宝的支付方法
func (z *ZhiFuBao) Pay(amount int64) {
    fmt.Printf("使用支付宝付款:%.2f元。\n", float64(amount/100))
}

// 定义微信的struct
type WeChat struct {
    // 微信
}

// Pay 微信的支付方法
func (w *WeChat) Pay(amount int64) {
    fmt.Printf("使用微信付款:%.2f元。\n", float64(amount/100))
}

// Payer 包含支付方法的接口类型
type Payer interface {
    Pay(int64)
}

// Checkout 结账,参数是实现了payer接口的obj
func Checkout(obj Payer) {
    // 支付100元
    obj.Pay(100)
}

func main() {
    Checkout(&ZhiFuBao{})
    Checkout(&WeChat{})
}
  
  • 空接口空接口是指没有定义任何方法的接口类型。因此任何类型都可以视为实现了空接口。也正是因为空接口类型的这个特性,空接口类型的变量可以存储任意类型的值。
 // Any 不包含任何方法的空接口类型
type Any interface{}
  

error接口

 // 返回了一个error
errors.New("报错啦")
  

并发

goroutine和wg

 func main() {
    // 来实现并发任务的同步执行
    // wg 防止main的goroutine执行完了之后,自己定义的goroutine还没有执行完
    var wg sync.WaitGroup  
    for i:=0; i<5; i++{
        go func(index int) {
            defer wg.Done()  // defer会在最后执行  wg.Done 计数器减1
            fmt.Println(index)
        }(i)
        wg.Add(1) // 计数器加1  这个数字是可以随便定义的,但是在Done里自己处理
    }
    wg.Wait()  // 阻塞,直到计数器变为0
    fmt.Println("meila")
}  

文章来源:智云一二三科技

文章标题:golang基础

文章地址:https://www.zhihuclub.com/98167.shtml

关于作者: 智云科技

热门文章

网站地图