go 笔记

  • 包名: 按照惯例, 包应当以小写的单个单词来命名,且不应使用下划线或驼峰记法。
  • 接口名:按照约定,只包含一个方法的接口应当以该方法的名称加上-er后缀来命名,如 Reader、Writer、 Formatter、CloseNotifier 等。
  • 在满足下列条件时,已被声明的变量 v 可出现在:= 声明中:
本次声明与已声明的 v 处于同一作用域中(若 v 已在外层作用域中声明过,则此次声明会创建一个新的变量§),
在初始化中与其类型相应的值才能赋予 v,且在此次声明中至少另有一个变量是新声明的。
  • 值得一提的是,即便Go中的函数形参和返回值在词法上处于大括号之外, 但它们的作用域和该函数体仍然相同。
  • 小写字母开头的函数,类型,变量,只在本包内可见,大写字母开头的函数,类型,变量才能被其他包使用
  • 切片动态增减元素,使用append方法,如果增加元素的是另外的切片,则需要使用append(mySlice,mySlice2...)三点
  • 在函数和方法中,如果参数是slice,那么本身传入的时候就是以地址的形式传入的
  • 数组切片支持copy()方法,用于将内容从一个切片复制到另外的一个切片
  • 浮点数的比较不能直接用==,可以自定义一个精度,再用两者的差的绝对值去和精度比较,如果小于精度值,则认为两者相等,和C语言类似。
import "math"
/**
判断两值是否相等
**/
func IsEqual(f1,f2,p float64) bool{
   return math.Abs(f1-f2) < p
}
  • 不能把函数的return语句放在 包含if...else分支中,否则会编译失败
  • switch是不需要别的语言中的default关键字的。 如果不设定swich后面的表达式,则相当于if...else...的作用;如果一个case紧跟下一个case,则需要在当前case中加上fallthrough关键字
  • go语言的for循环不支持以逗号为间隔的多个赋值语句,必须使用平行赋值的形式来初始化多个变量;break语句可以选择跳出哪一层。goto关键字可以跳到本函数内的某个标签
a := []int{1, 2, 3, 4, 5,6,7}
    JLOOP:
    for i,j := 0,len(a)-1;i < j; i, j =  i + 1, j-1 {
        a[i], a[j] = a[j], a[i]
        break JLOOP
    }
  • 一个加法函数
func Add(a,b int) (ret int,err error){
    if a < 0 || b < 0 {
        err = errors.New("Should be non-negative number")
    }
    return a+b, nil
}
  • 函数的不定参数,语法糖 ...type,再用for...range...进行迭代获取.如果希望传入任意类型的可以指定类型为interface{},如:
func printf(fomrt string, args ...interface{}){
}
  • 可以用 switch arg.(type)来进行变量的类型判断
  • panic()方法,接收任意的数据类型,调用时正常的函数执行流程将立即终止。
  • recover()函数用于终止错误流程处理,一般情况下,recover()应该在一个使用了defer 关键字的函数中执行以有效截取错误处理流程。
defer func(){
    if r := recover(); r != nil{
        log.Printf("Runtime error caught:%v",r)
    }

结构体:定义的一组字段的集合 结构体初始化,new(Student) == &Student{}是等价的。 接口:定义的一组方法的集合

  • go语言在面向对象的时,只有当需要修改对象的时候,才必须使用指针。它不是go语言的约束,而是一种自然约束。
func (a *Integer ) Add (b Integer) {
    retrun *a + b
}

go 结构体中的字段还有一个 在变量类型后还有一个tag,作为可选项,要获取tag内容,需要利用反射包来实现的。


  • 值类型:变量直接直接存储值,内存通常在栈上分配,基本数据类型int,float,bool,string,以及数组和struct
  • 引用传递:变量存储的是一个地址,这个地址存储最终的值,内存通常在堆上分配,通过GC回收,指针,slice,map,chan等都是引用类型

  • defer用途: 1.当函数返回时,执行defer语句,因此,可以用来做资源清理(比如数据库连接释放,锁释放)。 2.多个defer语句,按先进后出的方式执行。 3.defer语句中的变量,在defer 声明时就决定了。

内置函数 new:用来分配内存,主要用来分配值类型,比如int,struct,返回的是指针。 make:用来分配内存,主要用来分配引用类型,比如chan,map,slice,出现这种用差异的原因在于,这三种类型本质上为引用数据类型,它们在使用前必须初始化。 panicrecovery用来处理错误。


...有两个作用,一是作可变参数,另外可以把一个把一个slice展开


递归的设计原则: 1.一个大的问题能分解成相似的小的问题 2.定义好出口条件


闭包:一个函数和与其相关的引用环境组合而成的实体。 函数的返回值是一个函数


sort 包可以进行排序,使用sort.SearchInts()方法时需要传的参,slice必须是有序的


var mapkeTyPE 也可以用make初始化

a["hello"] = "world" //插入和更新 val,ok := a["hello"] //查找 delete(a,"hello") //删除 for k,v := range a{

fmt.Println(k,v)

}


锁机制: 1.互斥锁 Mutex

2.读写锁 Rwmutex

struct的内存布局,struct中所有字段在内存是连续的

*双链表定义:如果有两个指针分别这指向前一个节点和后一个节点,我们就叫双链表


链表:尾部插入法,头部插入法 type Student struct{ Name string Next *Student }


二叉树:如果每个节点有两个指针分别用来指向左子树和右子树,我们把这样的结构叫做二叉树 type Student struct{ Name string left *Studnent right *Student }

遍历时有深度优先和广度优先的方法 深度优先,可以用递归

广度优先,可以用队列


  • golang中没有构造函数,一般用工厂模式来解决问题
  • 再次强调,make用来创建map,slice,channel
  • new用来创建值类型,返回的是一个指针

在结构体中,结构体中的匿名字段可以实现其他语言中的所谓“继承”的效果,即一个结构体嵌套了另外一个匿名结构体。

结构体是用户单独定义的类型,不能和其他类型进行强制转换。

  • interface类型可以定义一组方法,但是这些不需要任何实现,并且interface不能包含任何变量。
  • golang中的接口,不需要显式的实现。只需要一个变量,含有接口类型中的所有方法,那么这个变量就实现这个接口。因此,golang中没有implement类似的关键字。
  • 如果一个变量含有了多个interface类型的方法,那么这个变量就实现了多个接口。
  • 一个接口可以嵌套在另外的接口。
  • 多态:一种事物的多种形态,都可以按照统一的接口进行操作
  • 类型断言:由于接口是一般类型,不知道具体类型,如果要转成具体类型,可以采用以下方法:
var t int
var x interface{}
x = t
y = x.(int)  //转成int  
或 y ,ok  = x.(int) //转成int,带检查

判断一个变量是否实现了某个接口,可以用
var v MyStruct
var f interface{}
f = v
if sv,ok := f.(Stringer){

}

还有这个:

swithc x.(type){

}

  • 反射:可以在运行时动态获取变量的相关信息

Import("reflect") 相关函数: a. reflect.TypeOf,获取变量的类型返回reflect.Type类型 b. reflect.ValueOf ,获取变量的值,返回reflect.Value类型 c. reflect.Value.Kind 获取变量的类别(如返回struct),返回一个常量,注意类别类型的区别 d. reflect.Value.Interface,转换interface{}类型

用反射操作结构体: a. relect.Value.NumField() 获取结构体中字段的个数 b. relect.Value.Method(n).Call来调用结构体中的方法


终端读写: 操作终端相关的句柄常量:

  • os.Stdin: 标准输入 (键盘等)
  • os.Stdout:标准输出(控制台等)
  • os.Stderr:标准错误
  • Sscanf可以中字符串中获取空格分隔
  • 带缓冲区的读写 bufio
  • 关闭一个文件 defer file.Close()

Errorf和error.New


  • 进程是资源分配和调度的独立单位
  • 线程是CPU调度和分派的基本单位
  • 一个进程可以创建和撤销多个线程,同一进程中的多个线程可以并发执行

并发和并行的区别:

  • 多线程程序在一个核的CPU上运行,就是并发
  • 多线程程序在多核CPU上运行,就是并行

协程和线程:

  • 协程: 独立的栈空间,共享堆空间,调度由用户自己控制,本质上有点类似于用户级线程,这些用户级线程的调度由自己实现的
  • 线程:一个线程上可以跑多个协程,协程是轻量级线程。

  • 协程并行访问全局变量时,需要给全局变量加锁

channel:

  • 类似于unit中的管道(pipe)
  • 先进先出
  • 线程安全,多个goroutine同时访问,不需要加锁
  • channel是有类型的,一个整数类型的channel只能存放整数

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 腾讯云函数在开发中的实践

    腾讯云函数在它的帮助文档里面有已经提到了它的几个具体实践,通过管中窥豹,我也来谈谈在具体业务中的几个实践。

    槽痞
  • mysql索引优化要点

    槽痞
  • go mod使用踩坑

    尝试使用了go mod去管理包,按照官方的文档指引https://blog.golang.org/using-go-modules进行实践。 整个过程中出现了几...

    槽痞
  • ava多线程:volatile变量、happens-before关系及内存一致性

    请参考来自 Jean-philippe Bempel 的评论。他提到了一个真实因 JVM 优化导致死锁的例子。我尽可能多地写博客的原因之一是一旦自己理解错了,可...

    哲洛不闹
  • 【Go 语言社区】Go 语言函数--转

    Go 语言函数 函数是基本的代码块,用于执行一个任务。 Go 语言最少有个 main() 函数。 你可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务...

    李海彬
  • Go 语言函数

    函数是基本的代码块,用于执行一个任务。 Go 语言最少有个 main() 函数。 你可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务。 函数声明告诉...

    李海彬
  • ReentrantReadWriteLock 源码分析以及 AQS 共享锁 (二)

    上一篇讲解了 AQS 的独占锁部分(参看:ReentrantLock 源码分析以及 AQS (一)),这一篇将介绍 AQS 的共享锁,以及基于共享锁实现读写锁分...

    烟雨星空
  • volatile和synchronized 实现原理的差别

    用户2141593
  • JavaScript中的闭包(closure)

    在JavaScript中,当一个内部函数被其外部函数之外的变量引用时,就形成了一个闭包。简单说,闭包就是能够读取其他函数内部变量的函数。

    刘亦枫
  • 线程同步

    多个线程同时访问1个数据时,如果只有读操作没有写操作可以不同步,如果写和读同时交互,就需要加锁,对数据进行同步,如STL容器是线程安全的,可以不考虑,除了少部...

    sofu456

扫码关注云+社区

领取腾讯云代金券