Go 语言基础语法学习 | 青训营笔记

180 阅读6分钟

这是我参与「第五届青训营」伴学笔记创作活动的第1天。

前言

作为一个Java Boy,这是我第一次接触Golang,两种语言都是面向对象的语言而且都因此记录下一下自己在上课过程中的笔记与个人思考。

知识点内容

作为一个有Java基础的人,我认为转Golang最开始的学习点,或者说从一门语言转向另一门语言最重要的是去适应新语言的语法,因此本篇知识点内容主要从语法层面入手。

1.初见Golang

大多数同学包括我在学习一门语言时都是从输出“Hello World”开始,因此,我们用Golang来实现下:

package main

import "fmt"

func main() {
   fmt.Println("Hello World")
}

从这个输出“Hello World”,我谈谈它给我的感受:首先它的表达式结尾加“;”或者不加都可以,但建议不加,而Java是必须加的;其次,函数的“{”一定和函数名在同一行,否则编译错误;再就是它导包的格式。

2.变量

Golang中提供了四种变量的声明方式,如下:

//方法一:声明一个变量,默认值是该变量类型的默认值,比如int为0
var a int
//方法二:声明一个变量并初始化一个值
var b int = 10 
//方法三:在初始化时省去数据类型,通过值自动匹配当前变量的数据类型
var c = 10
//方法四(常用):省去var关键字,直接通过值自动匹配
d := 10

这四种方法中,方法四最为常用,但需要注意的是方法四不支持全局变量的声明,但其他三种方法支持。另外,还有多变量的声明方式值得注意,分为单行写法和多行写法,如下:

//单行写法
var aa, bb = 10,10
var cc, dd = 10, "abc"
//多行写法
var (
   dd int  = 20
   ee bool = true
)

3.常量与iota

首先是常量的声明方式,如下:

const a int = 10

const(
   b = 10
   c = 20
)

将const与iota结合起来使用来表示枚举类型,可以在const()中添加一个关键字iota,每行的iota都会累加1,第一行的iota的默认值为0,如下:

const(
   a = iota  //a=0
   b         //b=1
   c         //c=2
)

同时,我们也可以在声明中加入运算改变每一行想要枚举的值,比如写作 a = 10*iota,那么值就会变成 a = 0,b = 10,c = 20。

4.函数

首先,先看看Golang函数的执行逻辑,如下图: 01.jpg 它区别于Java中的方法执行逻辑,Java中的方法即使有导包,依然是按照行顺序一行行来执行代码逻辑,只有在执行到被导入包调用的位置才会执行。这区别于Golan,Golang会先执行函数中导入包,如有导入的包中还有导入的包,则继续向下执行。

关于导包,也有以下几个知识点需要注意:

import _ “fmt”:给fmt包起⼀个别名,匿名, ⽆法使⽤当前包的⽅法,但是会执⾏当前的包内部的init()⽅法

import aa “fmt”:给fmt包起⼀个别名->aa,可以直接使用aa.方法名()来直接调⽤。

import . “fmt”:将当前fmt包中的全部⽅法,导⼊到当前本包的作⽤中,fmt包中的全部的⽅法可以直接使⽤API来调⽤,不需要fmt.API来调⽤

注:init()方法为函数的初始化方法,执行一个函数时,会最先调用这个方法。

5.切⽚slice

数组在Java中也是经常使用的,因此熟悉下Golang的数组也是至关重要的,Golang中的数组分为定长数组和动态数组(slice)。

定长数组:

定长数组声明的三种方式:

var Array1 [10]int
Array2 := [4]int{1, 2, 3, 4}
Array2 := [10]int{1, 2, 3, 4}

一个需要注意的点:定长数组在传参的时候是严格按照匹配数组类型的,就是说你的函数形参声明为需要一个定长4个长度的数组,你在给它传参就只能穿长度为4的数组。同时,这里在传参时为值拷贝,因此不会对原数组产生影响。

slice(动态数组):

slice声明的四种方式:

//声明slice1是一个切片且初始化,默认值为1、2、3,长度为3
slice1 := []int{1, 2, 3}

//声明slice2是一个切片,但没有给它分配空间
var slice2 []int
//开辟3个空间,默认值为0
slice2 = make(int[], 3)

//声明slice3是一个切片,同时给它分配空间,长度为3,初始值为0
var slice3 []int = make([]int, 3)

//声明slice4是一个切片,同时给它分配空间,长度为3,初始值为0,通过 := 推导出它是一个切片
slice4 := make([]int,3)

区别于定长数组,slice在传参上是引⽤传递,⽽且不同元素⻓度的动态数组他们的形参是⼀致。另外切片slice还有容量的追加以及截取方法。切片有一种扩容机制,在使用append的时候,如果⻓度增加后超过容量,则将容量增加2倍,这点类似于Java中的ArrayList的扩容机制。

6.map

应用很广泛的集合,Java中就有HashMap、LinkedHashMap、HashTable等,在Golang中同样有map,通过一个简单的案例学习下map的声明、添加、遍历、删除和修改:

//声明
bookMap := make(map[string]string)
//添加
bookMap["红楼梦"] = "曹雪芹"
bookMap["三国演义"] = "罗贯中"
bookMap["水浒传"] = "施耐庵"
//遍历
for key, value := range bookMap {
   fmt.Println("key = ", key, "value = ", value)
}
//修改
bookMap["水浒传"] = "小明"
//删除
delete(bookMap, "红楼梦")

Golang的map如果作为形参传递,是引用传递,传的实质上是map的指针。如果要对一个map进行拷贝,就再创建一个依次遍历赋值即可。

7.结构体struct

Go的结构体的概念和C++基本一致,一个比较通俗的理解,就是把多种基本数据类型组合在一起变成一个复杂的数据类型。有点类似于Java中的类,一个类中就包含很多数据类型,示例如下:

// 定义一个结构体
type Book struct {
   title string
   auth  string
}
func main() {
   //结构体的使用
   var book1 Book
   book1.title = "Golang"
   book1.auth = "cc"
}

和前面变量那部分一样,如果在传参时直接传结构体,传的是一个副本,对它的修改不会影响原结构体本身。因此,若想传递原结构体,需要用到指针,将值传递变为引用传递,即在作为形参传参时给结构体加上“*”,作为实参使用时加上“&”。

小结

通过本节课,我对Golang首先在语法层面上有了一定的熟悉,它的优势有很多,如:简单的部署(可直接编译成机器码可执⾏、不依赖其他库、直接运⾏即可部署)、静态类型语⾔(编译的时候即可检查出来隐藏的⼤多数问题)、强⼤的标准库(runtime系统调度机制、⾼效的GC垃圾回收、丰富的标准库)等等,当然,目前最直观的感受就是Golang相比于Java“又轻又快”,作为一门后端开发的语言,我认为它目前所缺少的是一个类似于Spring的生态,如果出现了,它在很多业务领域取代Java只是时间问题。我个人下一阶段的学习目标就是编程思维上的转变,把自己的Java思维转变成Golang的编程思维。

参考文档

Go语言圣经中文版