• Golang学习记录:基础知识篇(一)


    前言

    很久之前就想学Go语言了,但是一直有其他东西要学,因为我学的是Java嘛,所以后面学的东西一直是跟Java相关的。

    最近来到公司实习,需要用到Go语言,所以就趁着这个机会把Go学了。
    在这里插入图片描述

    什么是Golang?

    简单来说就是由Google公司的Robert Griesemer,Rob Pike和Ken Thompson设计的一种静态类型、编译型语言。它在2009年正式对外公开,目标是解决大规模软件工程中的问题。Go语言的语法简洁清晰,易于学习和使用,编译速度快,具有垃圾回收功能,并且拥有强大的标准库。

    Go语言的主要目标是将静态语言的安全性和高效性与动态语言的易开发性进行有机结合,达到完美平衡,从而使编程变得更加有乐趣,而不是在艰难抉择中痛苦前行。Go语言设计最本质的初衷就是简单,希望程序员的工作量最小化,利用Go本身少量的特性,并通过组合的方式去解决实际问题。

    Go语言的基础语法

    因为之前学过Java和C语言,所以我就主要记录一下他们之间的区别。

    我是用的vscode作为代码编辑器。

    语言结构

    Go 语言的基础组成有以下几个部分:

    • 包声明
    • 引入包
    • 函数
    • 变量
    • 语句 & 表达式
    • 注释

    接下来看下简单的代码,该代码输出了"Hello World!":

    package main
    
    import "fmt"
    
    func main() {
       /* 这是我的第一个简单的程序 */
       fmt.Println("Hello, World!")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    有点C语言的感觉有木有……

    • 第一行代码 package main 定义了包名。你必须在源文件中非注释的第一行指明这个文件属于哪个包,如:package main。package main表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。
    • import就是导包
    • func main() 是程序开始执行的函数。main 函数是每一个可执行程序所必须包含的,一般来说都是在启动后第一个执行的函数(如果有 init() 函数则会先执行该函数)。

    基础语法

    其实也和C语言差不多,和C语言不一样的有以下几个地方:

    1、在 Go 程序中,一行代表一个语句结束。每个语句不需要像 C 家族中的其它语言一样以分号 ; 结尾,因为这些工作都将由 Go 编译器自动完成。

    如果你打算将多个语句写在同一行,它们则必须使用 ; 人为区分,但在实际开发中我们并不鼓励这种做法。

    go语言保留的关键字有:
    在这里插入图片描述
    2、此外,在 Go 语言中,空格通常用于分隔标识符、关键字、运算符和表达式,以提高代码的可读性。

    Go 语言中变量的声明必须使用空格隔开,如:

    var x int
    const Pi float64 = 3.14159265358979323846
    
    • 1
    • 2

    这是因为在运算符和操作数之间要使用空格能让程序更易阅读。我平时敲代码没有敲空格的习惯,但是每次保存后,他竟然会自动给我把该有的空格给打上去了,很神奇。可能是我装了什么插件?

    对了,在go语言中IF表达式不用括号,我一开始不知道,后面因为我那个神奇的插件,每次我保存之后,他会默认给我把括号给干了,就像这样。

    if x > 0 {
        // do something
    }
    
    • 1
    • 2
    • 3

    3、go语言的类型定义一般写在语句的最后面,举个例子:

    //在C语言中,我们定义一个整型变量
    int x ;
    float pi = 3.14159265358979323846;
    
    
    //而在go语言中,通常这样写
    var x int
    const Pi float64 = 3.14159265358979323846
    
    //之后还会接触更简单的写法,像这样:
     pi := 3.14159265358979323846
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    那么为什么go语言要把数据定义放在后面,而不是像Java一样,放在变量前面嘞?

    因为数据类型放在变量名后面可以增加代码的可读性和可维护性。这种语法风格称为“后缀类型声明”。使用后缀类型声明,可以清晰地指定变量的数据类型,避免了在代码中使用多个变量时,由于数据类型不同而产生的混淆和错误。

    此外,Go语言的这种设计还有另一个重要的原因:Go语言支持类型推断,也就是说,在许多情况下,你可以省略变量的类型,让Go语言自动推断。这样做可以使代码更简洁,也更符合人类的阅读习惯。

    例如,在Go语言中,你可以写 var a = 20 。因为20是一个整数,所以Go语言可以自动推断出 a 的类型是 int。如果把类型放在变量名前面,那么当你想省略类型时,变量名就必须放在等号的右边,这样就打破了我们通常的阅读习惯。

    总的来说,Go语言把类型放在变量名后面,主要是为了提高代码的可读性、可维护性和简洁性。

    数据类型

    数据类型蛮多的,详情点击这里:Go语言数据类型

    问:为什么Go语言会有这么多数据类型嘞?比如 float 都分了一个“ float32 ”和“ float64 ”

    这是因为Go语言的数据类型设计理念主要是为了提供更多的灵活性和效率。数据类型的出现是为了把数据分成所需内存大小不同的数据,编程的时候需要用大数据的时候才需要申请大内存,就可以充分利用内存。

    Go语言提供了多种多样的数据类型,这些数据类型可以满足各种编程需求,使得Go语言在处理复杂的数据结构时更加方便和高效。

    此外,Go语言还提供了基于架构的类型,例如:intuintuintptr。这些类型的大小会根据运行程序的操作系统位数来确定,这样可以更好地利用硬件资源,提高程序运行效率。

    相比之下,Java语言的数据类型设计相对简单一些,主要包括八种基本数据类型和引用数据类型。这是因为Java语言的设计目标是“ 一次编写,到处运行 ”,因此它在数据类型设计上追求的是跨平台性和易用性。

    总的来说,Go语言在数据类型设计上提供了更多的选择和灵活性,以适应各种不同的编程需求和场景。

    问:比如我写了一句a, b, c, d := 20, 10, 15, 5 ,他会默认用int8还是int16其他类型?为什么嘞

    答:在Go语言中,当你使用 := 进行变量声明和初始化时,Go会根据右侧的值自动推断出变量的类型。例如,代码 a, b, c, d := 20, 10, 15, 5 中,因为20、10、15和5都是整数,所以Go会自动推断 abcd 的类型为 int

    这是因为Go语言的设计目标之一是代码的简洁性和易读性。通过自动类型推断,程序员可以省去在每次声明变量时都显式指定变量类型的麻烦,使得代码更加简洁易读¹。

    至于为什么默认使用 int 而不是 int8int16,这是因为在大多数情况下,int 类型已经足够满足需求,并且可以提供更好的性能。在Go语言中,int 类型的大小会根据运行程序的操作系统位数来确定。这样可以更好地利用硬件资源,提高程序运行效率。

    如果你需要使用特定大小的整数类型(如 int8int16),你可以在声明变量时显式指定类型。例如:var e int8 = 20。这样,变量 e 的类型就会被明确地设置为 int8

    基础使用

    简单总结一下这两天的使用体验:

    • IF…Else 语句: 和Java差不多,条件表达式没有括号;举个栗子:
    	// if, if else, else 语句
        a := 10
        if a == 10 {
            fmt.Println("a 等于 10")
        } else if a > 10 {
            fmt.Println("a 大于 10")
        } else {
            fmt.Println("a 小于 10")
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • For 循环语句: 和Java差不多,条件表达式没有括号;举个栗子:
    	// for 循环
        for i := 0; i < 5; i++ {
            fmt.Println(i)
        }
    
    • 1
    • 2
    • 3
    • 4
    • 运算符:基本一致,还没发现哪里不一样。如果后续发现了,再来补充修改
    • 自定义函数: 和Java完全不一样,类型写在后面,返回类型写在最后面;举个栗子:
    /* 函数返回两个数的最大值 */
    func max(num1, num2 int) int {
       /* 声明局部变量 */
       var result int
    
       if (num1 > num2) {
          result = num1
       } else {
          result = num2
       }
       return result 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 变量作用域: 和C语言一个样;局部变量写函数里面,全局变量拎出来;举个例子:
    package main
    
    import "fmt"
    
    /* 声明全局变量 */
    var g int
    
    func main() {
    
       /* 声明局部变量 */
       var a, b int
    
       /* 初始化参数 */
       a = 10
       b = 20
       g = a + b
    
       fmt.Printf("结果: a = %d, b = %d and g = %d\n", a, b, g)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 数组:语法格式如下:
    var arrayName [size]dataType
    
    • 1

    其中,arrayName 是数组的名称,size 是数组的大小,dataType 是数组中元素的数据类型。

    数组初始化
    以下实例声明一个名为 numbers 的整数数组,其大小为 5,在声明时,数组中的每个元素都会根据其数据类型进行默认初始化,对于整数类型,初始值为 0。

    var numbers [5]int
    
    • 1

    还可以使用初始化列表来初始化数组的元素:

    var numbers = [5]int{1, 2, 3, 4, 5}
    
    • 1

    另外,还可以使用 := 简短声明语法来声明和初始化数组:

    numbers := [5]int{1, 2, 3, 4, 5}
    
    • 1

    以上代码创建一个名为 numbers 的整数数组,并将其大小设置为 5,并初始化元素的值。

    注意!如果数组长度不确定,可以使用 … 代替数组的长度,编译器会根据元素个数自行推断数组的长度:

    var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
    或
    balance := [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
    
    • 1
    • 2
    • 3

    如果设置了数组的长度,我们还可以通过指定下标来初始化元素:

    //  将索引为 13 的元素初始化
    balance := [5]float32{1:2.0,3:7.0}
    
    • 1
    • 2

    访问数组元素没啥好说的,一维数组理解了,多维数组和函数传递数组也差不多了,传送门:Go语言多维数组向函数传递数组

    指针、结构体的定义就像之前变量的定义,然后用法和C语言基本一致,举两个栗子:

    指针:

    package main
    
    import "fmt"
    
    func main() {
       var a int= 20   /* 声明实际变量 */
       var ip *int        /* 声明指针变量 */
    
       ip = &a  /* 指针变量的存储地址 */
    
       fmt.Printf("a 变量的地址是: %x\n", &a  )
    
       /* 指针变量的存储地址 */
       fmt.Printf("ip 变量储存的指针地址: %x\n", ip )
    
       /* 使用指针访问值 */
       fmt.Printf("*ip 变量的值: %d\n", *ip )
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    结构体:

    package main
    
    import "fmt"
    
    type Books struct {
       title string
       author string
       subject string
       book_id int
    }
    
    
    func main() {
    
        // 创建一个新的结构体
        fmt.Println(Books{"Go 语言", "www.runoob.com", "Go 语言教程", 6495407})
    
        // 也可以使用 key => value 格式
        fmt.Println(Books{title: "Go 语言", author: "www.runoob.com", subject: "Go 语言教程", book_id: 6495407})
    
        // 忽略的字段为 0 或 空
       fmt.Println(Books{title: "Go 语言", author: "www.runoob.com"})
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    那么以上就是本次的内容了,在学习的过程中,可以多去敲敲代码,熟悉一下。也可以去菜鸟教程上面多看看,对新人挺友好的,也是我的公司同事推荐的教程网站。

    后续也会不定期更新学习记录和一些学习实验。🤠

  • 相关阅读:
    Studio One6.5安装源码教程
    《轻购优品》新零售玩法:消费积分认购+众筹新玩法
    21天挑战赛算法学习打卡——顺序查找
    5个.NET开源且强大的快速开发框架(帮助你提高生产效率)
    sentinel blockHandler不生效
    ChatGPT显现“ Something went wrong. If this issue persists ...”什么原因?如何解决?
    React Hooks
    icp许可证对网站的要求
    SpringMVC执行流程-JSP模式
    多线程指南:探究多线程在Node.js中的广泛应用
  • 原文地址:https://blog.csdn.net/qq_44386537/article/details/133845225