找回密码
 立即注册
首页 业界区 业界 Java程序员的Go入门笔记

Java程序员的Go入门笔记

骆贵 前天 21:37
系列文章目录和关于我
0.背景

3年java开发背景(因此这篇文章的特点是:比较适合java程序员doge),业余时间有了解过一些go,如今主要技术栈是go,此篇主要结合go语言圣经和团队内go项目,总结一些基础知识。
另外文章中没有对if,switch ,for进行说明,看多了文中的例子,自然就会这部分了
1.程序结构

1.1.声明、赋值和类型

Go语言主要有四种类型的声明语句:var、const、type和func,分别对应变量、常量、类型和函数实体对象的声明
以下是一个 Go 语言程序结构的代码示例:
  1. // 结构体声明
  2. type MyStruct struct {
  3.     name     string
  4.     age      int8
  5.     sex      bool
  6.     userType UserType
  7.     sub      *MyStruct
  8.     keys     []string
  9.     feature  map[string]any
  10. }
  11. // 类型
  12. type UserType int64
  13. // 常量声明
  14. const (
  15.     SUPER UserType = 1
  16. )
  17. func main() {
  18.     // 常量声明
  19.     const sexBool bool = false
  20.     // 变量
  21.     var userName string
  22.     // 变量赋值
  23.     userName = "username"
  24.     //简短变量声明并赋值
  25.     userAge := 1
  26.     // map类型
  27.     userFeature := make(map[string]any)
  28.     // map赋值
  29.     userFeature["key"] = "value"
  30.     // 数组类型
  31.     var keys []string = make([]string, 20)
  32.     //数组类型赋值
  33.     keys[0] = "!"
  34.     // 结构体
  35.     var subStruct = MyStruct{age: 1, userType: 1, sex: false, name: "1"}
  36.     myStruct := MyStruct{age: int8(userAge), userType: SUPER, sex: sexBool,
  37.     name: userName, feature: userFeature, sub: &subStruct, keys: keys}
  38.    
  39. }
复制代码
1.2.包和文件

包的概念和java中的包类似,不同的是导入包路径使用的是“/”进行分割
  1. package main
  2. import (
  3.     "errors"
  4.     "fmt"
  5. )
  6. import "code.byted.org/life_service/chenxinglandingdemo/compare" // 导入自定义的包
复制代码
该包中有一个文件int_comparator.go,定义了一个Compare函数
  1. type IntPriority interface {
  2.     GetPriority() int
  3. }
  4. func Compare(first IntPriority, second IntPriority) (int, error) {
  5.     if first == nil || second == nil {
  6.        return 0, errors.New("null input")
  7.     }
  8.     firstPriority := first.GetPriority()
  9.     secondPriority := second.GetPriority()
  10.     if firstPriority == secondPriority {
  11.        return 0, nil
  12.     }
  13.     if firstPriority > secondPriority {
  14.        return 1, nil
  15.     }
  16.     return -1, nil
  17. }
复制代码
引入包后的使用例子
  1. compare.Compare(&myStruct, &subStruct)
复制代码
其中大写开头的方法才被视为是public的,这点一开始让我觉得有点草率,但是似乎确实比java的private,protected,public用起来更爽一点
使用init方法可以对包文件的初始化,有点类似java类中的static静态代码块,但是无论该文件是否被使用,都会执行init,不像java只有使用到这个类执行类的初始化后才会执行static
  1. package compare
  2. import "fmt"
  3. func init() {
  4.     fmt.Println("init_method_learn.go")
  5. }
复制代码
init方法的执行是依赖文件名称顺序的,因此如果A文件使用B文件中的方法是,也许B文件还没有调用init
2.基本数据类型

2.1 整形

Go语言同时提供了有符号和无符号类型的整数运算。这里有int8、int16、int32和int64四种截然不同大小的有符号整数类型,分别对应8、16、32、64bit大小的有符号整数,与此对应的是uint8、uint16、uint32和uint64四种无符号整数类型。
这里需要注意的是,int 和 uint 类型的大小取决于操作系统的位数。在32位操作系统中,int 和 uint 类型的大小通常为4字节(32位);在64位操作系统中,它们的大小通常为8字节(64位)。我看我们系统中一般是没有直接使用int和unit的。
2.2 浮点数

Go语言提供了两种精度的浮点数,float32和float64。它们的算术规范由IEEE754浮点数国际标准定义,该浮点数规范被所有现代的CPU支持。
和其他语言一样,float32和float64都有一定精度误差
  1. var f float32 = 16777216
  2. // true
  3. fmt.Println(f+1 == f)
  4. var f64 float64 = 16777216
  5. // true
  6. fmt.Println(f64+0.000000000000001 == f64)
复制代码
在 IEEE 754 标准中,float32 类型的浮点数使用 32 位来存储,其中包括 1 位符号位(S)、8 位指数位(E)和 23 位尾数位(M)。对于数字 16777216,将其转换为二进制表示为 1000000000000000000000000。将其转换为 IEEE 754 格式的 float32 类型,具体步骤如下:

  • 符号位 S:16777216 是正数,所以符号位 S 为 0。
  • 指数位 E:将二进制数 1000000000000000000000000 右移 23 位,得到指数为 24。由于指数位的偏移量为 127,所以实际的指数值为 24 - 127 = -103。
  • 尾数位 M:取二进制数 1000000000000000000000000 的后 23 位,即 00000000000000000000000,省略掉开头的 1。
因此,16777216 在 IEEE 754 存储中的表示为:0 10000001 00000000000000000000000。
对于数字 16777217,按照同样的步骤转换为 IEEE 754 格式的 float32 类型:

  • 符号位 S:16777217 是正数,所以符号位 S 为 0。
  • 指数位 E:将二进制数 1000000000000000000000001 右移 23 位,得到指数为 24。由于指数位的偏移量为 127,所以实际的指数值为 24 - 127 = -103。
  • 尾数位 M:取二进制数 1000000000000000000000001 的后 23 位,即 000000000000000000000001,省略掉开头的 1。
所以,16777217 在 IEEE 754 存储中的表示也是:0 10000001 00000000000000000000000。
这就是为什么 16777216 和 16777217 在 IEEE 754 存储中看起来是一样的原因,它们的尾数位相同,而指数位也相同,只是在转换为十进制时,由于精度限制,会出现舍入误差,导致结果略有不同。
和java一样go也提供big来解决这个问题
  1. // 使用 math/big 包进行高精度计算
  2. a := new(big.Float).SetPrec(128).SetFloat64(0.000000000000001)
  3. b := new(big.Float).SetPrec(128).SetFloat64(16777216)
  4. c := new(big.Float).Add(a, b)
  5. // 输出1,表示c大于b,符合预期
  6. fmt.Println(c.Cmp(b))
复制代码
2.3 bool 布尔

类似于java中的boolean,在 Go 语言中,布尔型数据只有true和false两个值,没有像 Java 中那样的Boolean类型。
2.4 字符串
  1. func main() {
  2.     str := "testStr测试字符串"
  3.     // 输出22 ===>7+15(汉子3个字符)
  4.     fmt.Println(len(str))
  5.     // 输出116 utf8编码
  6.     var u uint8 = str[0]
  7.     fmt.Println(u)
  8.     // 输出116 utf8编码
  9.     fmt.Println(str[0])
  10.     // testStr
  11.     fmt.Println(str[0:7])
  12.     // testStr
  13.     fmt.Println(str[:7])
  14.     //测试字符串
  15.     fmt.Println(str[7:])
  16.     // 测试字符串
  17.     fmt.Println(str[7:len(str)])
  18.    
  19.     // 字符串循环
  20.     for i := range str {
  21.        fmt.Println(string(str[i]))
  22.     }
  23.    
  24. }
复制代码
如上是字符串常用的一些操作,go中的字符串也是不可变的
让我比较迷惑的是str[7:]这种字符串的操作似乎是深拷贝,但是有一些文档也说是浅拷贝
3.复合数据类型

3.1 数组
  1. // 声明,然后赋值
  2. ints := [10]int{}
  3. ints[1] = 1
  4. // 声明并赋值,没有赋值的index使用初值0
  5. var ints2 [20]int = [20]int{1, 2, 3, 4, 5}
  6. fmt.Println(ints2[19])
  7. fmt.Println(len(ints2))
  8. // 根据元素的个数来自动设置长度
  9. ints3 := [...]int{1, 2, 3, 4, 5}
  10. fmt.Println(len(ints3))
  11. ints4 := [...]int{99: -1}
  12. // 长度为100 = 99+1
  13. fmt.Println(len(ints4))
  14. ints5 := [5]int{1, 2, 3, 4, 5}
  15. // true
  16. fmt.Println(ints3 == ints5)
复制代码
其中我觉得比较有意思的是

  • 数组的比较:
如果一个数组的元素类型是可以相互比较的,那么数组类型也是可以相互比较的,这时候我们可以直接通过==比较运算符来比较两个数组,只有当两个数组的所有元素都是相等的时候数组才是相等的。不相等比较运算符!=遵循同样的规则。

  • 数组类型
[5]int和[20]int是不同的类型
因此两个不太类型的数组是不可以比较的
1.png

以及也不能把[5]int类型的变量使用=赋值一个[20]int 类型的变量
2.png

<ul>数组作为参数<ul>
数组作为参数是值传递,这意味着下面clearArray1方法是无法清空数组内容的,使用指针的clearArray2是可以清空的(这也启发我们,比较占用内存的变量应该使用指针,因为指针作为参数值拷贝浪费的内存少,拷贝的是指针对象!)

    1. func clearArray1(array [5]int) {
    2.     for i := range array {
    3.        array[i] = 0
    4.     }
    5. }
    6. func clearArray(array *[5]int) {
    7.     for i := range array {
    8.        array[i] = 0
    9.     }
    10. }
    复制代码
因为[5]int和[20]int是不太同的数组类型,因此上面两个函数,都只能穿入长度为5的数组,这一点让我觉得有点恶心
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册