从零开始的Go语言学习之路(一)

41 阅读6分钟

写在前面

为什么要学习Go语言

因为之前的项目有涉及到一些需要频繁读取写入文件的功能,这部分内容相对独立,如果直接用Java写,考虑到后面这部分有更新优化的话每次都要重新打包部署一份,挺麻烦的,要是能做成单独的可执行程序,每次就只需要上传一个最新的文件就行,不需要每次都停掉服务去更新。既然要开发成一个独立的可执行程序,那么就到了老生常谈的问题:拿什么写呢?Python?虽然写着很爽,但每次要打包整个环境,那为什么不直接用Java写呢;JavaScript?还不如Python;C/C++?可以是可以,但是没什么像样的包管理工具,搞不好全都要手搓,还有非常头疼的中文编码问题;Rust?所有权系统+Result打包不像是人学的。翻来找去调研半天发现呦!谷歌整的这个Go语言好像蛮不错的,有统一的包管理工具、有接近原生的性能,学习曲线还没有Rust陡峭,就决定是你了!

这个系列是什么

俗话说的好,好记性不如烂笔头,学习一门新的语言,总归是要记一些笔记的。那反正是要记笔记,不如直接分享出来,一是云存储方便自己多端复习,二是也能帮助其他像我一样想马上上手Go语言的jym。这个系列主要聚焦于Go语言本身的内容,不会去讨论如何安装或者配置Go,并且由于本人有其他编程语言的基础,所以有些地方会很笼统。

基础语法

由于目标是快速上手,因此基础语法部分仅侧重于变量声明、方法声明、逻辑语句这三部分。

变量声明

  • 使用var关键字声明变量,格式为: var + 变量名 + 类型 = 初始化值
var hello string = "hello"
  • 也可以不指定类型,由初始化值自动推断
var hello = "hello" // 自动推导为string类型
  • 一次性声明多个变量, 同种类型的变量可在声明完后统一声明类型
var hello, world string = "hello", "world"
  • 因式分解关键字声明方法,这种方法一般用于声明全局变量
var (
	hello string = "hello"
	world string = "world"
)
  • 对于不显式赋值的变量,默认为“零值”。这里的“零值”指的是不同类型变量的默认值,例如string类型的变量,其零值为空字符串;数值类型的变量,如intfloat,零值为0;bool类型的变量零值为false;指针类型的变量零值为nil,也就是空指针,等等
  • 可以使用象牙符号:=省略var关键字,直接声明并赋值,但是需要注意,已经通过var关键字声明的变量不能使用象牙符号赋值了
hello := "hello" // 省略var关键字,直接声明并赋值
// 对于已通过var关键字声明的变量,不得使用象牙符号重新赋值
var hello string
hello := "hello" // 编译报错!
  • 象牙符号也支持多变量声明
hello, world := "hello", "world" // 仍然需要保证该变量未被var关键字提前声明
  • 类似于Python,允许两个变量的值直接进行交换
var a, b = 1, 2
a, b = b, a // a, b的值被交换
  • 可以使用空白标识符_用于抛弃值
var a, b = 1, 2
_, b = b, a // 此时a的值被抛弃了
  • 常量使用const声明,也支持省略类型标注、多变量声明,但是常量只支持初始化为布尔型、数值型和字符串型
// 省略类型标注
const hello = "hello"
// 多变量声明
const hello, world string = "hello", "world"
// 因式分解方式
const(
    hello string = "hello"
    world string = "world"
)
// 采用因式分解方式声明时,其内部允许使用内置方法
const(
    hello string = "hello"
    world string = "world"
    size int = len(hello) // 内置方法len()
)

方法声明

  • 使用func声明一个方法
func hello(){}
  • 带参数的方法
func hello(msg string){}
// 多个同类型形参可共用同一个类型符
func hello(hello, world, msg string){}
  • 带返回值的方法
func hello() int {
    return 1 // 使用return返回值
}
// 返回多个值
func hello() (int, int) {
    return 1, 2
}
  • 匿名方法
// 匿名方法可以被赋值给一个变量
value := func(x float64) float64 {
    return x
}
value(3.1415926) // 使用方法

// 方法可以返回一个方法,下面的方法返回了一个没有参数、返回值类型为int的方法
// 由此可以实现类似于js的闭包效果
func getSequence() func() int {
    i := 0
    return func() int {
	i += 1
	return i
    }
}

// 由于方法可以被赋值给变量,因此也可以作为方法参数传递
value := func(x, y int) int { 
    return x + y 
} 
func plus(operator func(int, int) int, x, y int) int {
    return operator(x, y) 
}
plus(value, 1, 2) // 调用时将value方法作为参数传递

// 也可以直接在使用时传递匿名函数 
plus(func(x, y int) int {
    return x + y 
}, 1, 2)

逻辑语句

  • 条件语句:与Java或C++相比,省略了条件表达式的括号
a := 1

if a == 1 {
    // todo something
}else if a == 2 {
    // todo something
}else {
    // todo something
}
  • 循环语句:相较于传统的forwhiledo-while循环语句,Go语言统一采用for语句表示
// 标准for语句结构
for init; condition; post {}

// 示例
for i := 0; i < 10; i++ {
    // todo something
}

// 条件循环,类似于while
for condition {}

// 例如
a := 0
for a < 10 {
    // todo something
}

// 死循环
for {}

// 对于可迭代对象的循环
for item := range object {}
// 或
for key, value := range object {}
  • 模式匹配语句:使用switch关键字表示。注意:默认情况下,仅会执行匹配的第一个case分支,不会发生透传现象,若需要透传,可以使用fallthrough关键字指定透传的case
// 标准形式
switch condition {
    case situation:
        // todo something
    case situation:
        // todo something
    default:
        // default
}

// 例如
a := 1
if a == 1 {
    // todo something
}else if a == 2 {
    // todo something
}else {
    // todo something
}

// 使用fallthrough指定透传
a := 1
switch a {
    case 1:
        // todo something
        fallthrough
    case 2: // case1中使用了fallthrough关键字,因此当前case必然会被执行
        // todo something
    case 3: // case2中未使用fallthrough关键字,因此当前case需要判断
        // todo something
    default:
        // todo something
}
  • type-switch语句可以用于接口的类型判断
var x interface
switch x.(type){
    case string:
        // todo something
    case int:
        // todo something
    default:
        // todo something
}
  • select语句:这是一种特殊的模式匹配语句,一般用于通道通信,后面讨论协程时再作讲解

ok今天就学到这里,没有提及的内容,比如加减乘除、等于不等于、与或非运算符什么的基本跟Java C++之类的就没什么区别了,欢迎各位jym讨论交流,咱们下期再见!