走进Go语言-入门指南(基础语法) | 青训营

191 阅读10分钟

本篇幅主要介绍Go语言的基本语法 如变量常量的声明方式、条件执行语句、循环语句、数组、切片、哈希,等等。并在开头给出了更适合宝宝级别的入门安装 Go 教程。受限于篇幅常用特性将在下一篇文章中出现

  本文为青训营后端时间选题——Go语言入门指南:基础语法和常用特性解析

  作者也是第一次写作,如有错误的地方还望读者指正,谢谢

Part 1 开发环境(学习必备)

  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
    
  2. 配置 Go 语言集成开发环境,可以选择安装 VS Code / Goland ,

    • VS Code

      下载并安装后点击 拓展Ctrl+Shift+X​ 在搜索框内搜索 Go 安装即可,同时可以选择安装中文语言包

      ​​image-20230728211829-66p0nel.png​​

    • Goland (不是Golang)

      下载并安装,安装时注意要勾选环境变量安装。启动后出现Licenses (许可证) 页面,可采取 免费使用30天 / 在校学生申请教育许可证 使用

      image-20230725140941-28anv5k.png

      image-20230725141131-7l11dvl.png

Part 2 正式入门

1.简要Golang介绍

  ​image-20230728203736-cww5i19.png

  • 首先,什么是Go?

  Go语言称为 Golang,是在2009年由 Google 公司开发的一种静态强类型、编译型、并发型、并具有垃圾回收功能的编程语言。自面世以来它以高效的开发效率和完美的运行速度迅速风靡全球,被誉为“21 世纪的C语言”。

  Go 语言表现力强,且简单明了。它在设计时考虑了惯用语言,这使程序员能够高效地编写高效且可靠的代码。Go 语言之所以值得注意,部分原因在于它独特的并发机制,使得编写可同时利用多个内核的程序非常容易。Go 语言主要是一种强化静态类型的语言,这意味着变量类型在编译时是已知的。

  Go 与 C 语言有很多相似之处,它继承了 C 语言语法的许多方面,如控制流语句、基本数据类型、指针和其他元素等。不过,该语言的语法和语义均超出 C 语言。它还与 Java、C#、Python 等有相似之处。一般情况下,Go 语言往往从其他编程语言中借用并调整功能,同时去掉了大部分复杂性。

  • Go语言的特点?
  1. 高性能、高并发,搭配 Day 02 学习的 Goroutine 和 Channel,实现 CSP 模型
  2. 语法规则简单、严谨,没有歧义,使得代码简单易学
  3. 丰富的标准库,提供了丰富的数据结构和函数。不需要借助第三方库,可完成大部分的功能开发
  4. 完善的工具链,内置完整测试框架,编译、格式化、错误检查、帮助文档都有对应的工具
  5. 优秀的垃圾回收机制,从最开始的秒级别STW到目前的微秒级STW
  6. 学习曲线容易,规范简单灵活,有其他语言基础的程序员都能迅速上手。
  7. 开发效率和运行效率高,支持跨平台编译,部署方便。
  8. 快速编译,自由高效,不需要虚拟机或解释器,直接编译成机器码运行。
  • 目前使用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。

数字

  整型

  ​int8uint8

  ​int16uint16

  ​int32uint32

  ​int64uint64

  ​intuint​,具体长度取决于 CPU 位数。

  浮点型

  ​float32​​ float64​​

变量 & 常量声明

  常量,在程序编译阶段就确定下来的值,而程序在运行时无法改变该值。

  Go语言的变量声明有 2 种方式

  1. 此种方式一般会自动推导变量的类型,当然也可以手动定义
var name= "value" // 一般形式 使用var关键字
var a,b,c // 可一次声明多个变量
var a int = 1
var b = "Hello,World!"
var c = true
  1. 另外一种的变量定义方式 较为简短 :=​ 使用赋值操作符
d := float32(e)  //右边的值将赋值给左边

  因此 var a int = 1​ 与 a := 1​ 含义相同

  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 (哈希/词典)

  1. Map 集合是无序(无顺序之分)的 key-value 数据结构。KV对象用于 key-value 键值存储
  2. Map 集合中的 key / value 可以是任意类型,但所有的 key 必须属于同一数据类型,所有的 value 必须属于同一数据类型,key 和 value 的数据类型可以不相同。
  3. 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
	}
}