本篇幅主要介绍Go语言的基本语法 如变量常量的声明方式、条件执行语句、循环语句、数组、切片、哈希,等等。并在开头给出了更适合宝宝级别的入门安装 Go 教程。受限于篇幅常用特性将在下一篇文章中出现
本文为青训营后端时间选题——Go语言入门指南:基础语法和常用特性解析
作者也是第一次写作,如有错误的地方还望读者指正,谢谢
Part 1 开发环境(学习必备)
-
需要自行下载安装 Go 语言 / Go语言学习中文网 / 七牛云 - Goproxy.cn (Golang)
三种方法任选其一即可 前者可能需要正确网络环境,推荐使用中文网
针对自己的系统架构选择合适的版本,Windows用户下载
go1.20.6.windows-amd64.msi 文件即可,时过境迁可能版本号随时有变动,抓住关键词amd64msi 即可。下载并安装完成后 Win+R 打开 ^
cmd^ 输入go version 命令,若输出以下类似结果即为 Golang安装完成go version go1.20.6 windows/amd64 -
配置 Go 语言集成开发环境,可以选择安装 VS Code / Goland ,
Part 2 正式入门
1.简要Golang介绍
- 首先,什么是Go?
Go语言称为 Golang,是在2009年由 Google 公司开发的一种静态强类型、编译型、并发型、并具有垃圾回收功能的编程语言。自面世以来它以高效的开发效率和完美的运行速度迅速风靡全球,被誉为“21 世纪的C语言”。
Go 语言表现力强,且简单明了。它在设计时考虑了惯用语言,这使程序员能够高效地编写高效且可靠的代码。Go 语言之所以值得注意,部分原因在于它独特的并发机制,使得编写可同时利用多个内核的程序非常容易。Go 语言主要是一种强化静态类型的语言,这意味着变量类型在编译时是已知的。
Go 与 C 语言有很多相似之处,它继承了 C 语言语法的许多方面,如控制流语句、基本数据类型、指针和其他元素等。不过,该语言的语法和语义均超出 C 语言。它还与 Java、C#、Python 等有相似之处。一般情况下,Go 语言往往从其他编程语言中借用并调整功能,同时去掉了大部分复杂性。
- Go语言的特点?
- 高性能、高并发,搭配 Day 02 学习的 Goroutine 和 Channel,实现 CSP 模型
- 语法规则简单、严谨,没有歧义,使得代码简单易学
- 丰富的标准库,提供了丰富的数据结构和函数。不需要借助第三方库,可完成大部分的功能开发
- 完善的工具链,内置完整测试框架,编译、格式化、错误检查、帮助文档都有对应的工具
- 优秀的垃圾回收机制,从最开始的秒级别STW到目前的微秒级STW
- 学习曲线容易,规范简单灵活,有其他语言基础的程序员都能迅速上手。
- 开发效率和运行效率高,支持跨平台编译,部署方便。
- 快速编译,自由高效,不需要虚拟机或解释器,直接编译成机器码运行。
- 目前使用Go语言的公司有哪些?
目前很多公司都在使用Go语言来开发自己的服务,比如字节跳动,Google,B站,Facebook,甚至是美团,滴滴等等。字节跳动公司以前广泛使用Python,但是由于性能问题并且加上公司内部内部 RPC 和 HTTP 框架的推广使得公司内部都在使用Golang。Go语言是一种适合用来开发网络并发方面的服务,比如消息推送、监控、容器等,所以在高并发的项目上大多数公司会优先选择 Golang 作为开发语言。
Go语言的并发模型是基于CSP(Communicating Sequential Processes)模型设计的,这种模型可以让程序员更容易地编写出高效、安全、可靠的并发程序。
2.基础语法
2.1 命名(标识符)
如同其他编程语言一样,Go语言中所有的命名(函数名、变量名、常量名、类型名、语句标号和包名)都遵循
名字必需以字母或下划线开头,并且 Vacation 和 vacation 是俩个不同的名字,即Go语言大小写敏感
GO语言中有25个关键字。关键字同样不能作为命名,只能在特定语法环境中使用
break default func interface select
case defer go map struct
chan else goto package switch
const if range type fallthrough
continue for import return var
2.2 注释
注释其实只是很小的一part啦 但是对于新手来说,注释依然是很有必要的
注释的方法有俩种:分为 单行注释 和 多行注释
单行注释比较常见以 // 开始,多行注释以/* 开始 */ 结束
//这是一个单行注释 以//开始
、****/*
这是一个多行注释
*/ sdsd
2.3 变量&常量
var a = "initial"
var b, c int = 1, 2
var d = true
var e float64
f := float32(e)
g := a + "foo"
fmt.Println(a, b, c, d, e, f) // initial 1 2 true 0 0
fmt.Println(g) // initialapple
数据类型
在声明变量之前,咱们先了解下变量的数据类型,这篇文章主要涉及 字符串、布尔、数字。
变量类型有 字符串 整数 浮点型 布尔型
字符串
string
只能用一对双引号("")或反引号(``)括起来定义,不能用单引号('')定义!
布尔
bool
只有 true 和 false,默认为 false。
数字
整型
int8 uint8
int16 uint16
int32 uint32
int64 uint64
int uint,具体长度取决于 CPU 位数。
浮点型
float32 float64
变量 & 常量声明
常量,在程序编译阶段就确定下来的值,而程序在运行时无法改变该值。
Go语言的变量声明有 2 种方式
- 此种方式一般会自动推导变量的类型,当然也可以手动定义
var name= "value" // 一般形式 使用var关键字
var a,b,c // 可一次声明多个变量
var a int = 1
var b = "Hello,World!"
var c = true
- 另外一种的变量定义方式 较为简短
:= 使用赋值操作符
d := float32(e) //右边的值将赋值给左边
因此 var a int = 1 与 a := 1 含义相同
- 以下为常量的定义方式
Golang中常量没有确定的类型,会根据使用上下文自动确认类型。
//const a [type] = value
//[type] 可省略
const f string = "constant" //如果不赋值,使用的是该数据类型的默认值。
const g = 114514 //根据变量值,自行判断数据类型。
2.4 运算符
运算符的使用和优先级和C++类似 (算数运算符、关系运算符、赋值运算符、逻辑运算符 等等)
+ - * / % ++ -- (算数)这里不再赘述
2.5 条件语句
基础 if 语句以及if 嵌套语句这里不再赘述
if else 语句
if else 语句仍然需要提一嘴 因为和传统的C++ 不同,if 后的条件不需要用()包裹,即使使用编译器也会自动忽略
- Golang 中
if else 语句
package main
import "fmt"
var age int
func main() {
age = 30
if age < 18 {
fmt.Printf("年轻人")
} else if age >= 18 && age < 36 {
fmt.Printf("青壮年")
} else {
fmt.Printf("老人家")
}
}
- C++ 中的
if else 语句
if(boolean_expression) //与Golang不同的是 if 后的条件不需要使用`()` 分隔 当然编译器会自动忽略
{
return true;// 如果布尔表达式为真将执行的语句
}
else
{
return false;// 如果布尔表达式为假将执行的语句
}
注意事项
如上的C++代码 左大括号 { 可以单独放一行,但注意在Golang中这么做是**错误❌**的。
在其他大多数语言中,{ 的位置你自行决定。Go 比较特别,这是因为在Golang中我们注意到每个语句结束不必像 C++ 一样添加 ; 号作为结束。遵守分号注入规则(automatic semicolon injection):编译器会在每行代码尾部特定分隔符后加 ; 来分隔多条语句,比如会在 ) 后加分号:
// 错误示例
func main()
{
println("hello world")
}
// Golang 会理解为
func main(); // 无函数体
{
println("hello world");
}
switch 分支结构
switch 语句用于基于不同条件执行不同动作,每一个 case 分支都是唯一的,从上至下逐一测试,直到匹配为止。
switch 语句执行的过程从上至下,直到找到匹配项,匹配项后面也不需要再加 break。
case后可以直接添加条件
a := 2
switch a {
case 1:
fmt.Println("one")
case 2:
fmt.Println("two")
default:
fmt.Println("other")
}
C++ 与 Golang的switch语句不同点是switch 默认情况下 case 最后自带 break 语句,即golang中针对每个case不需要手动break(跳出)
当然如果想让其不要自带 break 语句,可以在case 后使用 fallthrough ,但fallthrough 不会判断下一条的 case 条件是否成立,无视条件执行。
2.6 for 循环语句
在 Golang 中 无 while 和 do while 循环 只有 for 循环
package main
import "fmt"
func main() {
i := 1
for {
fmt.Println("loop")
break
}
for j := 7; j < 9; j++ {
fmt.Println(j)
}
for n := 0; n < 5; n++ {
if n%2 == 0 {
continue
}
fmt.Println(n)
}
for i <= 3 {
fmt.Println(i)
i = i + 1
}
}
2.7 数组 Array
数组是一个由固定长度的特定类型元素组成的序列,一个数组可以由零个或多个元素组成,一旦声明了,数组的长度就固定了,不能动态变化。
len() 和 cap() 返回结果始终一样。
数组的每个元素可以通过索引下标来访问,索引下标的范围是从0开始到数组长度减1的位置。内置的len函数将返回数组中元素的个数。
package main
import "fmt"
func main() {
var a [5]int
a[4] = 100
fmt.Println("get:", a[2])
fmt.Println("len:", len(a))
b := [5]int{1, 2, 3, 4, 5}
fmt.Println(b)
var twoD [2][3]int
for i := 0; i < 2; i++ {
for j := 0; j < 3; j++ {
twoD[i][j] = i + j
}
}
fmt.Println("2d: ", twoD)
}
2.8 Slice 切片
固定长度不符合实际业务需求 切片是一个可变长度的数组
func main() {
s := make([]string, 3)
s[0] = "a"
s[1] = "b"
s[2] = "c"
fmt.Println("get:", s[2]) // c
fmt.Println("len:", len(s)) // 3
s = append(s, "d")
s = append(s, "e", "f")
fmt.Println(s) // [a b c d e f]
c := make([]string, len(s))
copy(c, s)
fmt.Println(c) // [a b c d e f]
fmt.Println(s[2:5]) // [c d e]
fmt.Println(s[:5]) // [a b c d e]
fmt.Println(s[2:]) // [c d e f]
good := []string{"g", "o", "o", "d"}
fmt.Println(good) // [g o o d]
}
Append
内置的 Append 函数用于向slice追加元素:
Append 函数 可追加数组的值 但需要注意 要把数字赋值给原数组
2.9 Map (哈希/词典)
- Map 集合是无序(无顺序之分)的 key-value 数据结构。KV对象用于 key-value 键值存储
- Map 集合中的 key / value 可以是任意类型,但所有的 key 必须属于同一数据类型,所有的 value 必须属于同一数据类型,key 和 value 的数据类型可以不相同。
- Map是一种映射,可以将键(
key)映射到值(value),格式为:map[keyType]valueType。声明一个map并初始化它,使用key:value进行初始化:
func main() {
m := make(map[string]int)
m["one"] = 1
m["two"] = 2
fmt.Println(m) // map[one:1 two:2]
fmt.Println(len(m)) // 2
fmt.Println(m["one"]) // 1
fmt.Println(m["unknow"]) // 0
r, ok := m["unknow"] //ok 用于获取这个map中有无这个key存在
fmt.Println(r, ok) // 0 false
delete(m, "one")
m2 := map[string]int{"one": 1, "two": 2}
var m3 = map[string]int{"one": 1, "two": 2}
fmt.Println(m2, m3)
}
2.10 Range
针对于slice 和 map 快速遍历
func main() {
nums := []int{2, 3, 4}
sum := 0
for i, num := range nums {
sum += num
if num == 2 {
fmt.Println("index:", i, "num:", num) // index: 0 num: 2
}
}
fmt.Println(sum) // 9
m := map[string]string{"a": "A", "b": "B"}
for k, v := range m {
fmt.Println(k, v) // b 8; a A
}
for k := range m {
fmt.Println("key", k) // key a; key b
}
}