JAVA开发的GO学习笔记

JAVA开发的GO学习笔记,第1张

JAVA开发的GO学习笔记 一、需要注意的点

1、没有public protect private这种可访问范围的关键字,而是使用大小写来代替,首字符大写,则对包外可见;首字母小写,只有包内可见。

2、每行的结尾不强制要求加“;”,也建议不要加,除非在同一行上写多行的代码,才需要。

3、多重变量定义方式:

  • var a int = 1
  • a := 1

4、自动类型推测,a := "test",能自动推测出变量a的类型是string。

5、支持指针类型(跟C语言的指针差不多)。

6、有特殊的channel类型,倡导“不要共享内存来实现通信,而是用通信来实现内存共享”,channel就是通信的通道。

7、数组切片slice的差别:

    数组:

  • 值类型,作为函数入参的时候,是copy一份数据,而不是传递原数组的引用。
  • 数组初始化之后,长度是固定的,无法修改长度。
  • 数组长度是Type的一种,[10]int和[20]int是不一样的类型。

    切片(动态数组):

  • 切片有长度len和容量cap的概念,长度是指已经被赋值过的最大下标+1,容量是指切片目前能容纳的最多元素个数(到达最大容量,继续追加数据,就会触发切换扩容,这又涉及到一个值得研究的问题:扩容是并发安全的么)。
  • 引用类型,作为函数入参的时候,传递的是引用。
  • 切片可以由数组或者另外一个切片产生,例如“s := arr[1:]”,这样切片s就会指向arr数组从下标1到结束的内容。当扩容的时候,就会脱离arr,指向新申请的地址。
  • 切片可以通过内置的append方法追加内容
  • 类似java的ArrayList。

声明数组的时候,[]内指定了长度或者...自动计算长度,就是数组;[]内没有内容就是切片。

参考文章:go语言中数组和切片的区别

8、接口:

go里的接口,不需要主动去实现,只要包含了接口定义的所有方法,就认为实现了这个接口。

如果定义一个没有任何方法的接口,则所有对象都实现了这个接口,这个接口类型的变量,能接受任何类型的值。

9、函数返回值可以有多个返回值,不需要像java一样,想返回多个值的时候,只能定义一个新的类,用这个类来存储值,方法返回这个类的对象。

10、go里的变量都有默认值,值类型的默认值是对应类型的0值,例如int32是0、string是"";引用类型的默认值是nil。

11、go里没有set,但是可以用Map来当Set使用。但是容易受0值的干扰。例如:

test_map := make(map[string]string)

a := test_map["test"]

这种情况,a的内容是"",无法判断是value就是"",还是没有test这个key

可以使用_, ok := test_map["test"],如果存在test的key,则ok=true,否则false。

删除key,用内置的delete方法delete(test_map, "test")。

12、常量定义关键字const,需要注意iota特殊常量~

可以看这个:Go 语言常量 | 菜鸟教程

13、if语句支持定义变量

if a := true; a {

  // dosomething

}

14、switch

  • case 可以有多个备选匹配值,例如:“case a==5, a==6,a==7”,当a是5、6、7里任意一个值的时候,都会匹配上
  • go语言里的case语句,不需要在末尾加break,匹配成功后,就不会执行其他case
  • 可以使用fallthrough,来实现匹配成功后,继续执行下一个case,但是不会判断case的条件

15、牛逼的select

有点像switch,实际效果像java的nio

  • 每个 case 都必须是一个通信
  • 所有 channel 表达式都会被求值
  • 所有被发送的表达式都会被求值
  • 如果任意某个通信可以进行,它就执行,其他被忽略
  • 如果有多个 case 都可以运行,Select 会随机公平地选出一个执行。其他不会执行。否则:.
    1. 如果有 default 子句,则执行该语句
    2. 如果没有 default 子句,select 将阻塞,直到某个通信可以运行;Go 不会重新对 channel 或值进行求值

package main

import "fmt"

func main() {

   var c1, c2, c3 chan int

   var i1, i2 int

   select {

      case i1 = <-c1:

         fmt.Printf("received ", i1, " from c1n")

      case c2 <- i2:

         fmt.Printf("sent ", i2, " to c2n")

      case i3, ok := (<-c3):  // same as: i3, ok := <-c3

         if ok {

            fmt.Printf("received ", i3, " from c3n")

         } else {

            fmt.Printf("c3 is closedn")

         }

      default:

         fmt.Printf("no communicationn")

   }   

}

16、defer(推迟),在函数体中使用defer语句,将在函数体结束的时候,执行defer的内容。适合用来实现资源的关闭,锁的释放

17、go使用的是协程,java使用的是线程

main方法运行在特殊的main goroutine,当main goroutine退出,其他gorountine也会退出。

如果运行go的机器是2核,则一般配置go启动两个2线程,相当于占用掉2个核。

使用goroutine的时候,就会创建一个协程,协程切换不涉及内核切换,都是在一个用户态中(还在同一个线程里,一个线程里的协程是串行的)。

线程的切换机制,是时间片用完了,就会切换。协程的切换时机有2种:

  • 新的协程被创建
  • 有协程的任务完成

gorountine相关runtime包:

  • runtime.Gosched()让出运行权
  • runtime.Goexit()退出goroutine,不会继续执行goroutine的代码,defer能触发

TODO:补上进程、线程和协程的差异

18、goto,go语言支持goto语句跳转到指定的label位置~自由又危险

19、go自带了依赖管理god.mod,不需要像java,需要额外依赖maven或者gradle

使用GoLand开发,默认是下载不了镜像的,要先去setting->Go->Go modules配置GOPROXY=https://goproxy.io

20、框架

  • web框架—gin
  • orm框架—gorm

21、Go默认的json序列化,时间默认的格式为RFC3339,即1993-01-01T20:08:23.000000028+08:00

但实际上我们一般接触更多的是1993-01-01 20:08:23

需要对time.Time进行一些包装:golang 自定义time.Time json输出格式 - 小风疏雨 - 博客园

二、待研究的内容

1、自动的垃圾回收,可以去研究一下垃圾回收机制~

2、切片slice的扩容机制,是否并发下是安全的

3、go的Mutex包的实现原理

4、go的依赖管理

5、channel的实现原理

三、相关学习文档

go的综合知识

GORM 中文文档

欢迎分享,转载请注明来源:内存溢出

原文地址: http://www.outofmemory.cn/zaji/5684139.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存