golang

主要从黄哥的资料笔记,尚硅谷,以及谢先斌大佬的笔记https://www.xiexianbin.cn/golang

以及https://exercism.org/上面进行练习, 顺便推荐一本书《go黑帽子》

GO语言概述

Go语言是谷歌2009年发布的第二款开源编程语言,它专门针对多处理器系统应用程序的编程进行了优化,它是一种系统语言其非常有用和强大,其程序可以媲美C或C++代码的速度,而且更加安全、支持并行进程。

Go支持面向对象,而且具有真正的闭包(closures)和反射 (reflection)等功能。

Go可以在不损失应用程序性能的情况下降低代码的复杂性。

Go是是静态强类型语言

Go语言开发者被叫做gopher,这个和信息查找系统gopher协议同名

Go语言特色

  • 简洁、快速、安全
  • 并行、有趣、开源
  • 内存管理、数组安全、编译迅速

Go语言用途

Go 语言被设计成一门应用于搭载 Web 服务器,存储集群或类似用途的巨型中央服务器的系统编程
语言。对于高性能分布式系统领域而言,Go 语言无疑比大多数其它语言有着更高的开发效率。
它提供了海量并行的支持,这对于游戏服务端的开发而言是再好不过了。

Go语言编译过程

image-20230117215732032

可查看文档网站信息

官网:
https://golang.google.cn/
API文档:
https://golang.google.cn/doc/
教程:
http://www.w3cschool.cn/go/go-tutorial.html
下载:
https://golang.google.cn/dl/

基础概念

基础概念将介绍三种主要的语言特性:包、函数和变量

Package

Go 应用程序以包的形式组织。包是位于同一目录中的源文件的集合。目录中的所有源文件必须共享相同的包名称。包名称通常是导入路径中的最后一个目录。

例如,

“math/rand”包中的文件以语句开头package rand

导入包时,只能使用/访问名称以大写字母开头的实体(函数、类型、变量、常量)。Go 中推荐的命名风格是标识符将使用 命名camelCase,除了那些意味着可以跨包访问的标识符应该是PascalCase

1
package lasagna

变量

Go 是静态类型的,这意味着所有变量在编译时都必须具有定义的类型。

可以通过显式指定类型来定义变量:

1
var explicit int // 显式声明

您还可以使用初始化器,编译器将分配变量类型以匹配初始化器的类型。

1
2
implicit := 10   // 隐式声明为int,自动分配类型
//也就是说可以利用 := 进行类型声明,其类型为其后数据的类型

声明后,可以使用运算符为变量赋值=。一旦声明,变量的类型就永远不会改变。

1
2
3
4
count := 1 // 赋初值
count = 2 // 更新新值

count = false // 由于分配了非“int”类型,这会引发编译器错误

常量

常量就像变量一样保存一段数据,但它们的值在程序执行过程中不能改变。

常量使用const关键字定义,可以是数字、字符、字符串或布尔值:

1
const Age = 21 // 定义一个值为 21 的数值常量 'Age'

函数

Go 函数接受零个或多个参数参数必须明确类型化,没有隐式声明类型。

return使用关键字从函数返回值。

通过指定函数名称并为函数的每个参数传递参数来调用函数。

请注意,Go 支持两种类型的注释:

单行注释在前面,多行注释在和//之间插入。/*``*/

1
2
3
4
5
6
7
8
9
10
11
package greeting

// Hello is a public function.
func Hello (name string) string {
return hi(name)
}

// hi is a private function.
func hi (name string) string {
return "hi " + name
}

*函数定义

func 函数名(形参列表) 返回类型列表 {
函数体
}

这里的返回类型列表是因为返回值需要描述返回值类型

函数调用

函数可以通过 函数名(实参列表),在调用过程中实参的每个数据会赋值给形参中的对应变量(实参列表类型和数量需要与形参一一对应)

【这和大部分代码的调用函数方法一样,不用多说】

*基础函数示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package main

import "fmt"

// 无参函数
func hello() {
fmt.Println("Hello World!")
}

// 有参函数,name 称为形参
func helloSomeone(name string) {
fmt.Println("Hello", name, "!")
}

// 有返回值函数
//func add(a int, b int) int {
func add(a, b int) int {
//函数声明中[a,b]存在多个相同类型[int]的连续形参,可以只保留最后一个形参的类型[a, b int]
return a + b
}

func ExampleFunc() {
// 无参函数调用
hello()
// 函数的标识符为 func(),调用函数需要加 ()
fmt.Printf("%T\n", hello)

// 有参函数调用
helloSomeone("xianbin") // name = "xianbin" 为实参,调用函数时,传递给函数的形参
fmt.Printf("%T\n", helloSomeone)

// 有返回值函数调用
sum := add(1, 2)
fmt.Println(sum)
fmt.Printf("%T\n", add)

// 函数的类型
var f func(int, int) int
//函数[func(int, int) int]也可以赋值给变量[var f],也可以当成实参[f(1, 2)]赋值给另一个函数[fmt.Println()]作为形参。
f = add
fmt.Println(f(1, 2))

// Output:
//Hello World!
//func()
//Hello xianbin !
//func(string)
//3
//func(int, int) int
//3
}

数字

Go 包含基本的数字类型,可以表示整数或浮点值的集合。

这个概念将集中在两种数字类型上:

  • int:例如0,,2552147483647大小至少为 32 位的带符号整数(值范围:-2147483648 到 2147483647)。但这将取决于系统架构。大多数现代计算机都是 64 位的,因此int大小为 64 位(取值率为:-9223372036854775808 到 9223372036854775807)。
  • float64:例如0.03.14。包含所有 64 位浮点数的集合。

+Go 支持, -, *,/%(余数不取模)的标准算术运算符集。

在 Go 中,不同类型之间的赋值需要显式转换。例如,要将 an int 转换为 a float64

您需要执行以下操作:an := float64(a)

1
2
3
4
5
6
7
8
var x int = 42
f := float64(x)

fmt.Printf("x is of type: %s\n", reflect.TypeOf(x))
// Output: x is of type: int

fmt.Printf("f is of type: %s\n", reflect.TypeOf(f))
// Output: f is of type: float64

计算

Go的计算符使用以及运算简写和大部分代码是一样

对于整数除法,余数被丢弃(例如5 / 2 == 2),也是一样的

简写,如

a+=5

a++

a–

不同类型的算术运算

在许多语言中,您可以对不同类型的变量执行算术运算,但在 Go 中,这会产生错误。例如:

1
2
3
4
5
6
7
var x int = 42

// this line produces an error
value := float32(2.0) * x // invalid operation: mismatched types float32 and int

// you must convert int type to float32 before performing arithmetic operation
value := float32(2.0) * float32(x)

这是由于这样高精度和低精度进行计算,会导致精度丢失,需要先将低精度类型转化为高精度类型,再进行计算

bool

和大部分代码一样

Go 中的布尔值由bool类型表示。booltruefalse

Go 支持三种布尔运算符:!(NOT)、&&(AND) 和||(OR)。

1
2
3
true || false // => true
true && false // => false
!true // => false

这三个布尔运算符各有不同的运算符优先级。因此,它们按以下顺序进行评估:!首先、&&第二和最后||。如果您想强制执行不同的顺序,您可以将布尔表达式括在圆括号中(即。()),因为圆括号具有更高的运算符优先级。

1
2
!true && false   // => false
!(true && false) // => true

if条件语句书写规范

如果习惯用

1
2
3
4
5
6
7
8
if(condition)
{
// do something
}
else
{
// do something1
}

那么在Go这里就行不通了,如果你按上面的格式进行书写,就会报错

unexpected else

你需要按照作者规定的格式,才会使得代码不显示错误

1
2
3
4
5
if condition {
// do something
}else {
// do something1
}

if+else if也是如此

1
2
3
4
5
6
7
8
9
if condition {
// do something
}else if condition1 {
// do something1
}else if condition2 {
// do something2
}else {
// do something3
}

Go的作者追求简洁优雅高效的代码格式,所以遇到这种形式,只能按作者的方式进行编写(无奈

关于字符串

Go 中的string是一个不可变的字节序列不一定代表字符

双引号之间定义了一个字符串文字:

1
const name = "Jane"

字符串可以通过+运算符连接起来:

1
2
"Jane" + " " + "Austen"
// => "Jane Austen"

一些特殊字符需要使用前导反斜杠进行转义,例如\t制表符和\n字符串中的新行。

1
2
3
4
"How is the weather today?\nIt's sunny"  
// =>
// How is the weather today?
// It's sunny

strings包包含许多用于处理字符串的有用函数。有关字符串函数的更多信息,请查看字符串包文档。这里有些例子:

1
2
3
4
5
6
7
8
9
import "strings"

// strings.ToLower returns the string given as argument with all its characters lowercased
strings.ToLower("MaKEmeLoweRCase")
// => "makemelowercase"

// strings.Repeat returns a string with a substring given as argument repeated many times
strings.Repeat("Go", 3)
// => "GoGoGo"

字符串包(strings)

关于字符串包

strings包包含许多用于处理字符串的有用函数。

1
2
3
import "strings"

strings.ToUpper("test") // => "TEST"

java中的包很相似

记几个常用的

strings.Repeat(str,num):重复str字符num次

strings.TrimSpace(str):清除str字符串左右边的空格

strings.TrimLeft/TrimRight(str,sign):清除str字符串左/右边的sign符号