Go语言学习笔记(三)

教程:文档 - Go 编程语言 (studygolang.com)

调用模块代码

在call-module-code需要注意,需要在hello目录下操作

go mod edit -replace example.com/greetings=../greetings

这是一个在Go项目的模块管理中的命令。在Go的模块管理工具(go mod)中,这个命令用于修改模块依赖关系。

具体来说,go mod edit -replace example.com/greetings=../greetings 这个命令的作用是:

  1. -replace: 这个选项表示你要替换一个已经存在的依赖。
  2. example.com/greetings: 这是你要替换的依赖的原始路径。
  3. ../greetings: 这是你要替换成的新路径。

所以,这个命令的意思是:将example.com/greetings这个依赖替换为项目根目录下的greetings目录。

简单来说,这个命令用于将一个远程依赖替换为本地路径的依赖。这在你想要使用本地版本的库而不是远程版本时非常有用,例如在开发过程中。

go mod tidy

go mod tidy 是一个 Go 语言的命令,用于自动添加或删除不必要的模块依赖项,使 go.mod 文件保持最新。

当你使用 Go 语言开发一个项目时,可能会使用 go get 命令来获取外部的依赖库。这些库会被添加到项目的 go.mod 文件中。随着时间的推移,有些依赖可能不再需要,或者新的依赖可能被添加进来。为了保持 go.mod 文件的整洁和一致性,你可以使用 go mod tidy 命令来自动处理这些不必要的依赖。

具体来说,go mod tidy 会做以下几件事:

  1. 删除不必要的依赖:如果一个依赖在代码中没有被使用,或者其版本与 go.mod 文件中指定的版本不匹配,那么这个依赖会被从 go.mod 文件中移除。
  2. 添加缺失的依赖:如果代码中使用了某个外部库,但这个库还没有被添加到 go.mod 文件中,那么 go mod tidy 会自动将其添加进来。
  3. 更新依赖的版本:如果某个依赖有新版本可用,并且这个新版本与 go.mod 文件中指定的版本不匹配,那么 go mod tidy 会自动更新这个依赖的版本。

总之,go mod tidy 是一个非常有用的命令,可以帮助开发者自动管理项目的模块依赖,确保 go.mod 文件始终是最新的。

 操作后hello文件夹下go.mod内容为

 如果不操作,则报错hello.go:6:2: no required module provides package example.com/greetings; to add it:
        go get example.com/greetings

处理错误

package greetings

import (
	"errors"
	"fmt"
)

// Hello returns a greeting for the named person.
func Hello(name string) (string, error) {
	if name == "" {
		return "", errors.New("empty name")
	}
	// Return a greeting that embeds the name in a message.
	message := fmt.Sprintf("Hi, %v. Welcome!", name)
	return message, nil
}
package main

import (
	"fmt"
	"log"

	"example.com/greetings"
)

func main() {
	// Get a greeting message and print it.
	message, err := greetings.Hello("")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(message)
}

使用日志

package main

import (
	"fmt"
	"log"

	"example.com/greetings"
)

func main() {
	log.SetPrefix("greetings: ")
	log.SetFlags(0)
	// Get a greeting message and print it.
	message, err := greetings.Hello("")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(message)
}

返回随机问候语

package main

import (
	"errors"
	"fmt"
	"log"
	"math/rand"
	// "example.com/greetings"
)

func Hello(name string) (string, error) {
	if name == "" {
		return name, errors.New("Empty name")
	}
	message := fmt.Sprintf(randomFormat(), name)
	return message, nil
}
func randomFormat() string {
	stringArray := []string{"Hi, %v. Welcome!",
		"Great to see you, %v!",
		"Hail, %v! Well met!"}
	index := rand.Intn(len(stringArray))
	return stringArray[index]
}
func main() {

	message, err := Hello("小明")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(message)
}

向多人问候

package greetings

import (
	"errors"
	"fmt"
	"math/rand"
)

func Hello(name string) (string, error) {
	if name == "" {
		return name, errors.New("Empty name")
	}
	message := fmt.Sprintf(randomFormat(), name)
	return message, nil
}
func randomFormat() string {
	stringArray := []string{"Hi, %v. Welcome!",
		"Great to see you, %v!",
		"Hail, %v! Well met!"}
	index := rand.Intn(len(stringArray))
	return stringArray[index]
}
func Hellos(names []string) (map[string]string, error) {
	cMap := make(map[string]string)
	for _, value := range names {
		message, err := Hello(value)
		if err != nil {
			return nil, err
		}
		cMap[value] = message
	}
	return cMap, nil

}

知识点:

1、函数入参为数组怎么写。

2、函数返回值为map怎么写

3、如何创建一个map   make(map[string]string)

package main

import (
	"fmt"
	"log"

	"example.com/greetings"
	// "example.com/greetings"
)

func main() {
	names := []string{
		"小明",
		"小王",
	}
	message, err := greetings.Hellos(names)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(message)
}

添加单元测试

package greetings

import (
	"regexp"
	"testing"
)

func TestHelloName(t *testing.T) {
	name := "Gladys"
	want := regexp.MustCompile(`\b` + name + `\b`)
	msg, err := Hello("Gladys")
	if !want.MatchString(msg) || err != nil {
		t.Fatalf(`Hello("Gladys")=%q,%v,want match for %#q,nil`, msg, err, want)

	}

}
func TestHelloEmpty(t *testing.T) {
	msg, err := Hello("")
	if msg != "" || err == nil {
		t.Fatalf(`Hello("") = %q, %v, want "", error`, msg, err)
	}

}

名为TestHelloName的测试函数,它接受一个类型为*testing.T的参数t。这是Go语言中用于编写测试的标准方式。 

TestHelloName方法若msg中不存在name或者err不为nil,则用例失败,

在vscode中,可以在测试函数前点击运行按钮运行,也可以在命令行运行go test或者 go test -v

 编译和安装应用程序

代码编译为可执行文件,生成hello.exe

go build

命令行下运行hello.exe

 安装软件包

go install

A Tour of Go 

 这个tour教程不错。

左边为教程,右边为实例

指针

Go 拥有指针。指针保存了值的内存地址。

类型 *T 是指向 T 类型值的指针。其零值为 nil

var p *int

& 操作符会生成一个指向其操作数的指针。

i := 42
p = &i

* 操作符表示指针指向的底层值。

fmt.Println(*p) // 通过指针 p 读取 i
*p = 21         // 通过指针 p 设置 i

这也就是通常所说的“间接引用”或“重定向”。

与 C 不同,Go 没有指针运算。

package main

import "fmt"

func main() {
	i, j := 42, 2701

	p := &i         // 指向 i
  fmt.Println(p)
	fmt.Println(*p) // 通过指针读取 i 的值
	*p = 21         // 通过指针设置 i 的值
	fmt.Println(i)  // 查看 i 的值

	p = &j         // 指向 j
	*p = *p / 37   // 通过指针对 j 进行除法运算
	fmt.Println(j) // 查看 j 的值
}

 

结构体

一个结构体(struct)就是一组字段(field)。

package main

import "fmt"

type Vertex struct {
	X int
	Y int
}

func main() {
	fmt.Println(Vertex{1, 2})
}

 

结构体字段

结构体字段使用点号来访问。

package main

import "fmt"

type Vertex struct {
	X int
	Y int
}

func main() {
	v := Vertex{1, 2}
	v.X = 4
	fmt.Println(v.X)
}

结构体指针

结构体字段可以通过结构体指针来访问。

如果我们有一个指向结构体的指针 p,那么可以通过 (*p).X 来访问其字段 X。不过这么写太啰嗦了,所以语言也允许我们使用隐式间接引用,直接写 p.X 就可以。

package main

import "fmt"

type Vertex struct {
	X int
	Y int
}

func main() {
	v := Vertex{1, 2}
	p := &v
	p.X = 1e9 //赋值 或者 (*p).X = 1e9 两种写法一样
	fmt.Println(v)
}

输出 

{1000000000 2}

结构体文法

结构体文法通过直接列出字段的值来新分配一个结构体。

使用 Name: 语法可以仅列出部分字段。(字段名的顺序无关。)

特殊的前缀 & 返回一个指向结构体的指针。

 

package main

import "fmt"

type Vertex struct {
	X, Y int
}

var (
	v1 = Vertex{1, 2}  // 创建一个 Vertex 类型的结构体
	v2 = Vertex{X: 1}  // Y:0 被隐式地赋予
	v3 = Vertex{}      // X:0 Y:0
	p  = &Vertex{1, 2} // 创建一个 *Vertex 类型的结构体(指针)
)

func main() {
	fmt.Println(v1, p, v2, v3)
}

数组

类型 [n]T 表示拥有 n 个 T 类型的值的数组。

表达式

var a [10]int

会将变量 a 声明为拥有 10 个整数的数组。

数组的长度是其类型的一部分,因此数组不能改变大小。这看起来是个限制,不过没关系,Go 提供了更加便利的方式来使用数组。

package main

import "fmt"

func main() {
	var a [2]string
	a[0] = "Hello"
	a[1] = "World"
	fmt.Println(a[0], a[1])
	fmt.Println(a)

	primes := [6]int{2, 3, 5, 7, 11, 13}
	fmt.Println(primes)
}

 

切片

每个数组的大小都是固定的。而切片则为数组元素提供动态大小的、灵活的视角。在实践中,切片比数组更常用。

类型 []T 表示一个元素类型为 T 的切片。

切片通过两个下标来界定,即一个上界和一个下界,二者以冒号分隔:

a[low : high]

它会选择一个半开区间,包括第一个元素,但排除最后一个元素。

以下表达式创建了一个切片,它包含 a 中下标从 1 到 3 的元素:

a[1:4]
package main

import "fmt"

func main() {
	primes := [6]int{2, 3, 5, 7, 11, 13}

	var s []int = primes[1:4]
	fmt.Println(s)
}

切片就像数组的引用

切片并不存储任何数据,它只是描述了底层数组中的一段。

更改切片的元素会修改其底层数组中对应的元素。

与它共享底层数组的切片都会观测到这些修改。

package main

import "fmt"

func main() {
	names := [4]string{
		"John",
		"Paul",
		"George",
		"Ringo",
	}
	fmt.Println(names)

	a := names[0:2]
	b := names[1:3]
	fmt.Println(a, b)

	b[0] = "XXX"
	fmt.Println(a, b)
	fmt.Println(names)
}

修改b的第一个值,切片a和数组中该值都被更改。 

切片文法

切片文法类似于没有长度的数组文法。

这是一个数组文法:

[3]bool{true, true, false}

下面这样则会创建一个和上面相同的数组,然后构建一个引用了它的切片:

[]bool{true, true, false}
package main

import "fmt"

func main() {
	q := []int{2, 3, 5, 7, 11, 13}
	fmt.Println(q)

	r := []bool{true, false, true, true, false, true}
	fmt.Println(r)

	s := []struct {
		i int
		b bool
	}{
		{2, true},
		{3, false},
		{5, true},
		{7, true},
		{11, false},
		{13, true},
	}
	fmt.Println(s)
}

 

切片的默认行为

在进行切片时,你可以利用它的默认行为来忽略上下界。

切片下界的默认值为 0,上界则是该切片的长度。

对于数组

var a [10]int

来说,以下切片是等价的:

a[0:10]
a[:10]
a[0:]
a[:]
package main

import "fmt"

func main() {
	s := []int{2, 3, 5, 7, 11, 13}

	s = s[1:4]
	fmt.Println(s)

	s = s[:2]
	fmt.Println(s)

	s = s[1:]
	fmt.Println(s)
}

切片的长度与容量

切片拥有 长度 和 容量

切片的长度就是它所包含的元素个数。

切片的容量是从它的第一个元素开始数,到其底层数组元素末尾的个数。

切片 s 的长度和容量可通过表达式 len(s) 和 cap(s) 来获取。

你可以通过重新切片来扩展一个切片,给它提供足够的容量。试着修改示例程序中的切片操作,向外扩展它的容量,看看会发生什么。

package main

import "fmt"

func main() {
	s := []int{2, 3, 5, 7, 11, 13}
	printSlice(s)

	// 截取切片使其长度为 0
	s = s[:0]
	printSlice(s)

	// 拓展其长度
	s = s[:4]
	printSlice(s)

	// 舍弃前两个值
	s = s[2:]
	printSlice(s)
}

func printSlice(s []int) {
	fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
len=6 cap=6 [2 3 5 7 11 13]
len=0 cap=6 []
len=4 cap=6 [2 3 5 7]
len=2 cap=4 [5 7]

nil 切片

切片的零值是 nil

nil 切片的长度和容量为 0 且没有底层数组。

package main

import "fmt"

func main() {
	var s []int
	fmt.Println(s, len(s), cap(s))
	if s == nil {
		fmt.Println("nil!")
	}
}

 

[] 0 0
nil!

Go 语言之旅 (go-zh.org) 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot-admin健康监控

监控-健康监控服务 目的:能够理解健康监控actuator的作用 背景: 在一些大型的业务应用中,工程会根据业务模块做微服务拆分,后期每一个微服务在云上部署以后,都需要对其进行监控、追踪、审计、控制等操纵&#xff0c…

chatglm3的api调用

conda activate chatglm3 cd openai_api_demo python openai_api.py 启动ok,然后内网映射后 anaconda启动jupyter !pip install openai1.6.1 -i https://pypi.tuna.tsinghua.edu.cn/simple/ """ This script is an example of using the OpenAI …

人工智能复习

机器学习中线性回归和逻辑回归: 机器学习的分类: 监督学习和无监督学习,半监督学习 监督学习(Supervised Learning): 监督学习是一种利用带有标签(标记)的数据进行训练的机器学习…

【学习总结】地面路谱分析

本文仅用于记录自己的学习总结,包括个人理解。不保证内容严格正确。 0. 参考资料 [1] 国标GB/T 703-2005/ISO 8608:1995。[2] Bilibili-车辆考研-路面不平度统计特性[3] Bilibili-清华大学《汽车理论》[4] 网络参考文档.[5] 论文:高雄《路面不平度统计…

什么是Helm?它是如何提升云原生应用私有化部署效率的

转载至我的博客 ,公众号:架构成长指南 试想一下,如果有一个项目有50 个微服务,每个微服务都有service、deployment、ingress、pvc等 yaml 文件,算下来大概有 200 个文件,然后这个项目需要基于k8s进行私有化…

强化学习求解TSP(四):Qlearning求解旅行商问题TSP(提供Python代码)

一、Qlearning简介 Q-learning是一种强化学习算法,用于解决基于奖励的决策问题。它是一种无模型的学习方法,通过与环境的交互来学习最优策略。Q-learning的核心思想是通过学习一个Q值函数来指导决策,该函数表示在给定状态下采取某个动作所获…

Vue3-41-组件- 动态组件 component 标签 和 is 属性 的使用

说明 <component> 标签 有一个 is 属性&#xff0c; 可以给这个 is属性 赋值为一个 组件对象&#xff0c; 这样这个<component> 标签就可以渲染指定的组件对象了。 使用案例 本案例中会 准备两个简单的组件&#xff0c; 在 App.vue 中导入这两个组件&#xff0c;并…

C#入门篇(一)

变量 顾名思义就是变化的容器&#xff0c;即可以用来存放各种不同类型数值的一个容器 折叠代码 第一步&#xff1a;#region 第二步&#xff1a;按tab键 14种数据类型 有符号的数据类型 sbyte&#xff1a;-128~127 short&#xff1a;-32768~32767 int&#xff1a;-21亿多~21亿多…

VMware Visio OmniGraffle模板和图标

VMware Visio OmniGraffle模板和图标 包含可用于Visio、omnigraffle的图标和SVG矢量图。 简介 这组资源适用于 IT 管理员、系统架构师、网络工程师和其他需要可视化 VMware 基础架构的专业人士创建精确的 VMware 网络和数据中心部署图&#xff0c;通过使用这些模板和图标&am…

css三大特性

css 三大特性 一、层叠性&#xff1a;css样式冲突采取原则&#xff08;后者覆盖前者&#xff09; 二、继承性&#xff1a;对于部分属性样式会有天生的继承 &#xff08;1&#xff09;字体系列属性 font-family&#xff1a;字体系列 font-weight&#xff1a;字体的粗细 fon…

ai中的渐变怎么使用

Adobe Illustrator 是Adobe系统公司推出的基于矢量的图形制作软件&#xff0c;作为全球最著名的矢量图形软件&#xff0c;以其强大的功能和体贴用户的界面&#xff0c;已经占据了全球矢量编辑软件中的大部分份额。据不完全统计全球有37%的设计师在使用Adobe Illustrator进行艺术…

一键修复所有dll缺失的工具,dll修复工具下载使用教程

在计算机使用过程中&#xff0c;我们经常会遇到各种软件或系统错误提示&#xff0c;其中最常见的就是“找不到指定的模块”或“无法找到某某.dll文件”。Dll是动态链接库的缩写&#xff0c;它是Windows操作系统中的重要组成部分&#xff0c;负责提供各种功能和资源给应用程序使…

Kafka集群部署 (KRaft模式集群)

KRaft 模式是 Kafka 在 3.0 版本中引入的新模式。KRaft 模式使用了 Raft 共识算法来管理 Kafka 集群元数据。Raft 算法是一种分布式共识算法&#xff0c;具有高可用性、可扩展性和安全性等优势。 在 KRaft 模式下&#xff0c;Kafka 集群中的每个 Broker 都具有和 Zookeeper 类…

NVIDIA GPU 与服务器型号匹配查询

NVIDIA GPU 与服务器型号匹配查询 1. Qualified System Catalog (认证服务器目录)2. NVIDIA L40S2.1. NVIDIA L40S GPU Specifications References 1. Qualified System Catalog (认证服务器目录) https://www.nvidia.cn/data-center/data-center-gpus/qualified-system-catal…

mapboxGL中区域掩膜的实现

概述 区域掩膜的功能也是比较常见的功能呢&#xff0c;本文分享在mapboxGL中结合canvas如何实现。 效果 实现 1. 创建画布 先创建一个map大小的canvas&#xff0c;设置其大小与样式&#xff0c;并添加到地图画布容器中。 const {width, height} map.getCanvas() canvas …

软件开发平台应用价值高吗?

我们都知道&#xff0c;随着行业的进步和社会的发展&#xff0c;低代码开发平台也拥有了非常可观的发展前景。利用软件开发平台&#xff0c;可以实现提质增效的办公效率&#xff0c;办公流程化发展也将提上日程。那么&#xff0c;您知道软件开发平台都拥有哪些优势特点吗&#…

OCP NVME SSD规范解读-6.标准日志要求-2

STD-LOG-12:针对日志存储的类型定义了多种&#xff0c;复位&#xff08;包括控制器复位&#xff0c;NSSR、FLR、PCIe hot reset&#xff09;与断电重启POWER CYCLE有不同的操作要求。 STD-LOG-14: Lockdown命令是NVMe管理命令集中的一个命令&#xff0c;主要用于安全和管理目的…

抖店开通之后需要操作什么?开店后的相关流程分享,附出单建议

我是王路飞。 抖店开通了之后&#xff0c;都需要操作什么呢&#xff1f; 一个是店铺的基础搭建&#xff0c;可以帮助你熟悉和了解抖店的各项功能&#xff0c;提高后续的运营效率&#xff1b; 一个是定类目&#xff0c;前期最重要的事情&#xff0c;没有之一&#xff1b; 之…

【SQL】对表中的记录通过时间维度分组,统计出每组的记录条数

场景&#xff1a;一般用作数据统计&#xff0c;比如统计一个淘宝用户在年、月、日的维度上的订单数。 业务&#xff1a;一个集合&#xff0c;以时间维度来进行分组求和。 准备一张订单表order&#xff0c;有一些常规属性&#xff0c;比如创建时间&#xff0c;订单号。 DDL语句如…

LeetCode 225.用队列实现栈(详解) ૮꒰ ˶• ༝ •˶꒱ა

题目详情&#xff1a; 思路&#xff1a;1.定义两个队列用于存储栈的数据&#xff0c;其中一个为空。 2.对我们定义的栈进行入数据&#xff0c;就相当于对不为空的队列进行入数据。 3.对我们定义的栈进行删除&#xff0c;相当于取出不为空的队列中的数据放到为空的队列中&#x…