Go语言教程(一看就会)

news2024/11/16 11:25:24

 

全篇文章 7000 字左右, 建议阅读时长 1h 以上。  

Go语言是一门开源的编程语言,目的在于降低构建简单、可靠、高效软件的门槛。Go平衡了底层系统语言的能力,以及在现代语言中所见到的高级特性。它是快速的、静态类型编译语言。

第一个GO程序

package main // 程序组织成包 (1)

import "fmt" // 格式化输出数据 (2)

// 主函数入口 (3)
func main() {
    fmt.Println("你好世界") // 输出语句 (4)
}

逐行解析这个程序

  • (1) 这里是每个go文件必备的,如果当前文件是独立执行必须要使用 package main
  • (2) 引入了一个名为 fmt 的库包。
  • (3) 当go程序执行时,首先调用的就是main.main()函数
  • (4) 调用了fmt库中的Println函数,在屏幕中打印字符串信息。

构建和运行Go程序

  • 构建需要在命令行中输入 go build 文件名.go, 执行后会生成一个同名的可执行文件。
  • 命令行中输入 ./文件名 即可运行

如果你没有本地的Go语言环境,可以通过浏览器在线方式学习: https://go.dev/play/

一、数据类型

1.1 变量

Go语言是一种静态类型的编程语言。

可以通过 var 声明一个或多个变量

var str = "apple"

也可以通过 := 语法来进行初始化变量的简写

str := "apple"

以上两种创建方式应用代码如下:

package main

import "fmt"

func main() {
	var a = "saycode" // 字符串
	fmt.Println(a)

	var b, c int = 1, 2 // 整型
	fmt.Println(b, c)

	var d = true 	// 布尔型
	fmt.Println(d)

	var e int		// 声明变量类型为 int
	fmt.Println(e)

    // 简化方式
	f := "apple" // 字符串
	fmt.Println(f)

	g := true	// 布尔型
	fmt.Println(g)
}

多个var声明可以成组

var (
    x int,
    y bool
)

如果涉及到多个变量同类型的情况,可以进行平行赋值。

// 多行
name := "saycode"
age := 10

// 平行
name, age := "saycode", 10

特殊变量 _(下划线)

对于下划线而言,任何值赋值给它,都会被舍弃。程序将3赋值给b,1进行舍弃。

_, b := 1, 3

 1.2 常量

常量是可不变的值,Go语言支持字符、字符串、布尔值和数字值的常量。

使用 const 关键字声明

错误案例

运行当前程序发现报错cannot assign to name (untyped string constant "I Like Go"),也就证实了,常量进行初始化值后,是不可以进行改变的。

package main

import "fmt"

func main() {
    const name := "I Like Go"
    name = "I Like Java"

    fmt.Println(name)
}

正确案例

将π作为常量进行声明,接着去计算出圆的面积。

package main

import "fmt"

const PI = 3.14

func main() {
	// 计算圆的面积
	const r = 2
	const area = PI * r * r

	fmt.Println(area)
}

二、格式化输出

2.1 默认方式

如果不确定要用什么,可以直接使用%v (最好使用特定)

fmt.Printf("我今年 %v 岁", 20)
// 我今年 20 岁
fmt.Printf("我叫 %v", "张三")
// 我叫 张三

2.2 字符串

当需要特定插入字符串时,可使用 %s

fmt.Printf("我叫 %s", "张三")

2.3 十进制整数

当需要特定插入十进制整数时,可使用%d

fmt.Printf("我今年 %d 岁", 10)
// 我今年 10岁

2.4 浮点数

当需要插入浮点数时,可使用 %f

.数字f (.2f),含义就是保留小数点后两位

fmt.Printf("我今年 %f 岁", 10.22)
// 我今年 10.220000岁
fmt.Printf("我今年 %.2f 岁", 10.22)
// 我今年 10.22岁

2.5 变量类型

当需要查看当前变量类型时,可使用%T

package main

import "fmt"

func main() {
    
	num := 10
	fmt.Printf("num类型为 %T", num)
}

三、控制结构

3.1 条件判断if

if语句是一种用于判断条件的结构,他将根据布尔表达式,结果就是 (true 或 false)的结果来决定是否执行某段代码。

else 是不满足前一个 if 后去执行的代码块。

如下代码就是判断 x > 5(布尔表达式), 如果大于则执行"x大于5",否则执行 "x小于或等于5"

if x > 5 {
    fmt.Println("x大于5")
} else {
    fmt.Println("x小于或等于5")
}

3.2 if的嵌套

可以通过嵌套的方式去判断多个值

if x > 5 {
    fmt.Println("x大于5") 
} else if x < 5 {
    fmt.Println("x小于5")
} else {
    fmt.Println("x等于5")
}

if语句可以有初始化语句,初始化语句中创建的变量只在if语句块中使用。

以下代码是通过getLength方法去获取email字符串的长度,在去对长度进行判断大小是否小于1。

package main

import "fmt"

func main() {
	email := "nazhanpeng@163.com"
    // 语法糖创建
	if length := getLength(email); length < 1 {
		fmt.Println("邮箱长度小于1")
	} else {
		fmt.Println("邮箱没问题")
	}

}

func getLength(a string) int {
	return len(a)
}

3.4 goto

可以使用goto去跳转到当前函数的内定标签位置。例如以下示例。

package main

import "fmt"

func myGoto() {
	i := 1
Position:	// 定义跳转目标标签(注意要以冒号结尾)
	fmt.Println(i)
	i++	// i++ == i+1
	if i == 10 {	// 限制输出10次以内
		return
	}

	goto Position	// 跳转到目标标签
}

func main() {
	myGoto()
}

3.5 for循环

for循环的写法有三种形式

(1)、for 初始化语句; 条件语句; 后置语句 { } 正常循环

package main

import "fmt"

func main() {
	sum := 0
	for i := 0; i < 10; i++ {
		sum += i	//  将i的值进行累加
	}
	fmt.Println("sum = ", sum)
}

(2)、for 条件语句 { } 和while一样

package main

import "fmt"

func main() {

	sum, i := 0, 0

	for i < 10 {
		sum += i
		i++
	}

	fmt.Println("sum = ", sum)

}

(3)、for { } 死循环

package main

import "fmt"

func main() {
	for {
        fmt.Println("我爱学 Go")
    }
}

3.6 break

利用break可以终止当前语句的执行。下面循环打印了0-5。

package main

import "fmt"

func main() {
	for i := 0; i < 10; i++ {
		if i > 5 {
			break // 终止当前循环
		}
		fmt.Println("i=", i)
	}
}

3.7 continue

可以让循环进入下一次迭代,也就是跳过当前这一次的循环。下面循环打印了0-9,但是当i=5时,跳过了。

package main

import "fmt"

func main() {
	for i := 0; i < 10; i++ {
		if i == 5 {
			continue
		}
		fmt.Println("i=", i)
	}
}

3.8 switch

从上到下去执行switch的代码块,直到找到匹配项,如果switch没有表达式,会去匹配true。

package main

import "fmt"

func main() {
	i := 1

	switch i {	// 检测i的值是否有匹配项
	case 0:	// case 值,为匹配项
		fmt.Println("i=0")
	case 1:
		fmt.Println("i=1")
	}
}

当我进行匹配时,想让它向下进行匹配时,需要用到 fallthroungh 关键字。下面当i=0时,会自定向下匹配,去执行对应语句。

package main

import "fmt"

func main() {
	i := 0

	switch i {
	case 0:
		fallthrough
	case 1:
		fmt.Println("寻找到了", i)
	}
}

我们也可以去指定当没有任何匹配项时的默认行为,使用 default 关键字。下面当i=2时,会默认去执行默认行为。

package main

import "fmt"

func main() {
	i := 2

	switch i {
	case 0:
		fallthrough
	case 1:
		fmt.Println("寻找到", i)
	default:	// 如果i不等于0和1,则默认执行
		fmt.Println("默认执行")
	}
}

也可以在一个case中匹配匹配多个值,使用逗号进行分隔。下面将1-5的数字进行分隔。

package main

import "fmt"

func main() {
	i := 1

	switch i {
	case 1, 2, 3, 4, 5: // 逗号相当于 或,也就是 1 或 2 或 3 或 4 或 5
		fmt.Println("i=", i)
	}
}

四、数组

数组是一种固定长度、同类型元素的集合。数组的长度在声明时就被确定,并且无法改变。

4.1 创建数组

var 数组名 [数组长度]数组类型

var nums [5]int
var names [3]string

4.2 数组初始化

可以在声明数组的同时去进行初始化

nums := [5]int{1, 2, 3, 4, 5}
names := [3]string{"张三", "李四", "王五"}

对于数组长度可以使用省略号来进行替换,这样编译器会通过初始化值的数量去判断数组的长度。

nums := [...]int{1, 2, 3, 4, 5}

对于访问数组元素,可以通过数组下标来进行访问。 数组下标都是以0开始。下面有一个整数数组1到5。它的下标值是这样的。

下面声明一个1到5元素的数组,对数组元素进行访问。

package main

import "fmt"

func main() {
	arr := [5]int{1, 2, 3, 4, 5} // 声明数组
	fmt.Println("arr[0]=", arr[0]) // 访问下标0位置的元素
	fmt.Println("arr[2]=", arr[2]) // 访问下标2位置的元素
}

4.3 遍历数组的两种方式

(1)、通过for循环进行遍历数组。

package main

import "fmt"

func main() {
	nums := [...]int{1, 2, 3, 4, 5}

	for i := 0; i < len(nums); i++ {
		fmt.Println(nums[i])
	}
}

(2)、通过for循环进行遍历数组。 

range 是一个迭代器,使用时会在循环的内容中返回一个键值对。下面是一个range循环的一个写法, k是键,v是值。range后面紧接着遍历数据

for k, v := range slice/array/string/map/channel { }

下面是使用range 去遍历一个nums 的一个数组的例子。

package main

import "fmt"

func main() {
	nums := [...]int{1, 2, 3, 4, 5}

	for index, value := range nums {
		fmt.Printf("索引: %d, 值: %d\n", index, value)
	}
}

4.4 声明多维数组

var 数组名 [数组长度][数组长度]数组类型

var nums [3][4]int // 声明一个 3*4的二维整数型数组

可以在声明多维数组时,直接进行初始化。

package main

import "fmt"

func main() {
	nums := [3][4]int{
		{1, 2, 3, 4},
		{5, 6, 7, 8},
		{9, 10, 11, 12},
	}

	fmt.Println(nums)
}

初始化后的样子如下。

当我们对部分值进行初始化,未被初始化的位置将被赋值为0。

package main

import "fmt"

func main() {
	nums := [3][4]int{
		{1, 2},
		{5, 6, 7},
	}

	fmt.Println(nums)
}

初始化后的样子如下。

4.5 访问和修改多维数组

可以通过索引访问和修改多维数组的元素。

package main

import "fmt"

func main() {
	nums := [3][4]int{
		{1, 2, 3, 4},
		{5, 6, 7, 8},
		{9, 10, 11, 12},
	}

	fmt.Println(nums)

	nums[1][2] = 10
	fmt.Println(nums[1][2])
}

对于遍历多维数组,可以使用for循环嵌套来进行遍历。下面程序中i代表的是多维数组的行,j代表的是多维数组的列,也就是多维数组要是用两个下标才可以进行访问。

package main

import "fmt"

func main() {
	nums := [3][4]int{
		{1, 2, 3, 4},
		{5, 6, 7, 8},
		{9, 10, 11, 12},
	}

	for i := 0; i < len(nums); i++ {
		for j := 0; j < len(nums[i]); j++ {
			fmt.Printf("nums[%d][%d]=%d\n", i, j, nums[i][j])
		}
	}
}

上面程序中nums数组的下标值如下。

五、slice

动态数组(slice)是对数组的抽象。它可以改变长度和容量,并能共享底层数组的数据。

5.1 创建slice

var s []int // 声明一个整数类型的 动态数组

从另一个数组中创建动态数组

arr := [5]int{1, 2, 3, 4, 5}
s := arr[1:4] // 创建一个包含 arr中从索引1到索引3元素的动态数组

s2 := s[1:2] // 创建一个基于s的动态数组

5.2 make函数

可以使用内置 make 函数来创建一个指定长度和容量的slice。下面所说的长度为5,容量为10,是说会创建可以容纳10个的slice,默认插入5个为0的整数。

package main

import "fmt"

func main() {
	s1 := make([]int, 5) // 长度为5的整数。
	s2 := make([]int, 5, 10) // 长度为5,容量为10的整数。

	fmt.Println(s1)
	fmt.Println(s2)

}

也可以通过字面量的方式去进行初始化。

s := []int{1, 2, 3, 4, 5}

5.3 len函数与cap函数

假设我们创建了一个slice,可以通过len函数和cap函数来获取对应的长度和容量。

package main

import "fmt"

func main() {
	s := []int{1, 2, 3, 4, 5}
	fmt.Println("长度: ", len(s)) // 5
	fmt.Println("容量: ", cap(s)) // 5
}

5.4 追加元素

通过使用内容函数 append向slice内追加元素,并且会返回追加后的slice

var 数组名 [数组长度][数组长度]数组类型

package main

import "fmt"

func main() {
    s := []int{1, 2, 3, 4, 5}
    s = append(s, 4, 5)
    fmt.Println(s) // [1 2 3 4 5]
}

如果被追加的slice 没有足够的容量去存储追加的元素,append 会分配一个足够大的slice来存放原有slice和追加的元素。

package main

import "fmt"

func main() {
    s0 := []int{0, 1}
    s1 := append(s0, 2) // 追加一个元素2, [0 0 2]
    s2 := append(s1, 3) // 追加一个元素3, [0 0 2 3]
}

5.5 copy函数

copy函数可以从slice中复制元素到新的slice。会返回复制的元素的个数。

package main

import "fmt"

func main() {
	var a = [...]int{0, 1, 2, 3, 4, 5}
	var s = make([]int, 4)
	l1 := copy(s, a[0:]) // 从slice 0开始复制并存储到s中, [0 1 2 3]
	fmt.Println(s)
	fmt.Println("l1=", l1)

	l2 := copy(s, s[2:]) // 从slice 2开始复制并存储到s中, [2 3 2 3]
	fmt.Println(s)
	fmt.Println("l2=", l2)
}

5.6 遍历 slice

可以使用for循环进行遍历

package main

import "fmt"

func main() {
    s := []int{1, 2, 3, 4, 5}
    for i := 0; i < len(s); i++ {
        fmt.Println(s[i)
    }
}

也可以使用for range循环遍历

package main

import "fmt"

func main() {
    s := []int{1, 2, 3, 4, 5}
    for index, value := range s {
        fmt.Printf("索引: %d, 值: %d\n", index, value)
    }
}

六、函数

一个基本的函数需要包含函数名、参数列表、返回值类型和函数体。

例如定义一个函数名为add的函数,包含两个参数a、b,返回值类型为int类型,函数体是a+b计算两个整数的和。

func add(a int, b int) int {
    return a + b
}

函数可以有0个或多个参数。

4.1 返回结果

一般用于去终止函数并返回结果。在Go中可以返回单个值或多个值。

单个值返回已经在上面返回了。

4.1.1 多个值返回

package main

import "fmt"

func divide(a int, b int) (int, int) {
    quotient := a / b
    remainder := a % b
    return quotient, remainder
}

func main() {
    q, r := divide(4, 3)
    fmt.Println(q,r)
}

4.1.2 命名返回值

命名返回值在函数代码块内为局部变量,可以进行使用。

package main

import "fmt"

func rectangleArea(width, height int) (area int) {

    area = width * height
    return
}

func main() {
    area := rectangleArea(5,6)
    fmt.Println("area", area)
}

4.1.3 空返回语句

可以使用空return返回结果

package main

import "fmt"

func swap(a, b int) (x, y int) {
    x = b
    y = a
    return
}

func main() {
    x, y := swap(1,2)
    fmt.Println("x", y, "y", y)
}

4.1.4 按照值传递变量

意味着当一个变量传递给一个函数时,该函数收到的是该变量的副本。

我们发现x的值还是5,就说明函数无法去改变传递变量的值。

package main

import "fmt"

func main() {
	x := 5
	increment(x)

	fmt.Println("x=", x)

}

func increment(x int) {
	x++
}

明天继续更新,请关注我

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1956217.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一篇文章带你入门爬虫并编写自己的第一个爬虫程序

一、引言 目前我们处在一个信息快速迭代更新的时代&#xff0c;海量的数据以大爆炸的形式出现在网络之中&#xff0c;相比起过去那个通过广播无线电、书籍报刊等传统媒介获取信息的方式&#xff0c;我们现在通过网络使用搜索引擎几乎可以获得任何我们需要的信息资源。 但与此同…

Python3网络爬虫开发实战(7)JavaScript 动态渲染页面爬取

文章目录 一、Selenium1. 基本安装2. 基本使用3. 声明浏览器对象4. 访问页面5. 查找节点6. 节点交互7. 动作链8. 执行 JavaScript9. 获取节点信息10. 切换 Frame11. 延时等待12. 前进后退13. Cookies14. 选项卡管理15. 异常处理16. 反屏蔽17. 无头模式18. Pyppeteer&#xff0c…

《遥远的救世主》读后感

未完待续。。。。 未完待续。。。。 未完待续。。。。 【经典语录】 01. 我们这个民族总是以有文化自居&#xff0c;却忘了问一句&#xff1a;是有什么文化&#xff1f;是真理真相的文化还是弱势文化&#xff1f;是符合事物规律的文化还是违背事物规律的文化&#xff1f;任何…

shell脚本与sed基本语法

Day11 一、shell 基础 1、shell 概念 shell 英文翻译过来是外壳的意思&#xff0c;作为计算机语言来理解可以认为它是 操作系统的外壳。可以通过shell 命令来操作和控制操作系统&#xff0c;比如 Linux中的shell命令就包括 ls、cd、pwd 等等。 2、shell 在内核的基础上编写的…

第一个设计模式——单例模式

目录 一、特点&#xff1a; 二、实现单例模式步骤 三、饿汉式 四、懒汉式 五、双重检查锁 六、静态内部类 七、枚举 八、可能被反序列化和反射破坏什么意思&#xff1f; 九、如何解决呢&#xff1f; 一、特点&#xff1a; 唯一性&#xff0c;单例模式确保程序中只有一…

甘肃粉条:一口爽滑,满心欢喜

在甘肃的美食世界里&#xff0c;粉条是一道独具特色的存在&#xff0c;它以其爽滑的口感和多样的烹饪方式&#xff0c;赢得了无数人的喜爱。甘肃食家巷粉条&#xff0c;选用当地优质的土豆或红薯为原料&#xff0c;经过一系列精细的加工工艺&#xff0c;最终成就了这一根根晶莹…

SSRF (服务端请求伪造)

&#x1f3bc;个人主页&#xff1a;金灰 &#x1f60e;作者简介:一名简单的大一学生;易编橙终身成长社群的嘉宾.✨ 专注网络空间安全服务,期待与您的交流分享~ 感谢您的点赞、关注、评论、收藏、是对我最大的认可和支持&#xff01;❤️ &#x1f34a;易编橙终身成长社群&#…

2-48 基于matlab的EM算法聚类可视化程序

基于matlab的EM算法聚类可视化程序&#xff0c;通过期望最大化算法&#xff08;EM&#xff09;优化类别间距&#xff0c;使得类别间距最大、类内间距最小。输出聚类前后结果及收敛曲线。程序已调通&#xff0c;可直接运行。 2-48 期望最大化算法&#xff08;EM&#xff09; 聚类…

6/9-axis imu sensor/姿态传感器 学习板/开发板 开源 MPU6500 QMC5883 加速度 陀螺仪 地磁传感器

1-应用领域&#xff1a; 游戏交互、3D模型控制、机器人、设备姿态检测、翻转状态检测、无人机、无人船、无人车、VR/AR、AHRS、姿态算法研究与分析&#xff0c;短距无效姿态测量、车辆调平系统&#xff0c;机器震动检测 2-产品硬件规格: 尺寸: 蓝牙:5.0 电池:默认150ma&…

TCP程序设计

TCP概述 建立连接 客户端和服务器端在建立连接时&#xff1a; 服务端是典型的监听接受连接的模式&#xff0c;就是ListenAccept 客户端是主动建立连接的模式&#xff0c;就是Dial Go语言中使用 net包实现网络的相关操作&#xff0c;包括我们TCP的操作。 用于建立连接的典型…

tusiart吐司艺术图像生成、LoRA 模型的使用和训练网站

文章目录 前言一、Tusiart&#xff08;吐司艺术&#xff09;是什么二、Tusiart&#xff08;吐司艺术&#xff09;主要功能三、Tusiart&#xff08;吐司艺术&#xff09; 网站图片四、Tusiart&#xff08;吐司艺术&#xff09; 相关地址总结 前言 每天分享一个关于AI项目或者网…

【系统架构设计师】二十、云原生架构设计理论与实践①

目录 一、云原生架构内涵 二、云原生的原则 三、主要架构模式 四、典型的云原生架构反模式 相关推荐 一、云原生架构内涵 云原生架构是基于云原生技术的一组架构原则和设计模式的集合&#xff0c;旨在将云应用中的非业务代码部分进行最大化的剥离&#xff0c;从而让云设施…

SQL Server索引碎片的基本知识(附Demo)

目录 前言1. 基本知识2. 检索碎片2.1 dm_db_index_physical_stats2.2 DBCC SHOWCONTIG 3. 修复和优化 前言 索引碎片太高本身会阻碍查询的效率&#xff0c;这个问题要重视 1. 基本知识 索引中的数据页不再连续&#xff0c;导致存储和检索数据时的效率降低 碎片通常发生在以…

虚拟机启动电脑蓝屏问题解决方案

1.查看CPU虚拟化是否开启&#xff0c;没有开启的可以按照教程开启 打开任务管理器&#xff0c;查看是否开启CUP虚拟化 如果没有开启,可以查看下面的链接&#xff0c;进入BIOS开启 win10如何开启虚拟化支持_win10开启cpu虚拟化的方法&#xff0d;系统城 2&#xff0c;控制面板…

C#中的同步编程和异步编程

1. 简单描述一下同步编程和异步编程 同步编程&#xff1a;按照代码的顺序一行一行执行&#xff0c;如果某个操作需要等待&#xff08;比如读取文件、网络请求、数据库操作等&#xff09;&#xff0c;那么当前的线程就会停下来&#xff0c;一直到这个操作完成了之后&#xff0c…

无坚不摧的Python重试机制:探索Tenacity库

无坚不摧的Python重试机制&#xff1a;探索Tenacity 库 背景&#xff1a;为何选择Tenacity&#xff1f; 在软件开发中&#xff0c;我们经常面临需要重试操作的场景&#xff0c;比如网络请求、数据库操作等。这些操作可能会因为各种原因暂时失败&#xff0c;但稍后可能会成功…

更换CentOS Stream 8镜像源

CentOS Stream 8替换阿里云镜像源 确认CentOS版本 hostnamectl备份当前配置 sudo cp -r /etc/yum.repos.d /etc/yum.repos.d.backup创建临时文件下载目录 mkdir -p /tmp/aliyun-repos cd /tmp/aliyun-repos下载 .repo 文件列表并解析链接 wget -r -np -nd -A ".repo&…

ssm框架整合,异常处理器和拦截器(纯注解开发)

目录 ssm框架整合 第一步&#xff1a;指定打包方式和导入所需要的依赖 打包方法&#xff1a;war springMVC所需依赖 解析json依赖 mybatis依赖 数据库驱动依赖 druid数据源依赖 junit依赖 第二步&#xff1a;导入tomcat插件 第三步&#xff1a;编写配置类 SpringCon…

C++知识点总结:2.类和对象(自用)

类和对象 1. 类和对象的关系2. 对象指针3. 在堆上创建对象4. 成员访问限定符5. 名字编码&#xff08;Name Mangling&#xff09;6.构造函数7.构造函数的重载8.初始化列表8. 成员变量初始化的顺序&#xff08;通过初始化列表&#xff09;9. 初始化 const 成员变量10. 析构函数11…

安装 moleculeSTM 踩坑日记

“学习 LLM &#xff0c;在大模型时代为自己存张船票”。 相信很多人都有这样的想法。那么&#xff0c;在 AI for science 领域&#xff0c;哪些 LLM 模型值得一试呢&#xff1f; 笔者认为&#xff1a; LLM 直接预测 SMILES 性质 or 直接生成 SMILES 的技术路线是行不通的。因…