Golang教程一(环境搭建,变量,数据类型,数组切片map)

这篇具有很好参考价值的文章主要介绍了Golang教程一(环境搭建,变量,数据类型,数组切片map)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、环境搭建

1.windows安装

2.linux安装 

3.开发工具

二、变量定义与输入输出

1.变量定义

2.全局变量与局部变量

3.定义多个变量

4.常量定义

5.命名规范

6.输出

格式化输出

7.输入 

三、基本数据类型

1.整数型

2.浮点型

3.字符型

4.字符串类型

转义字符

多行字符串

5.布尔类型

四、数组、切片、map

1.数组

 2.切片

make函数

切片面试题 

3.Map

map面试题


一、环境搭建

官网

https://go.dev/dl/

访问不了的就访问中文网就好了

go安装包下载

https://studygolang.com/dl

安装指定版本的安装包就好了

1.windows安装

选择 xxx.windows-amd64.msi

Golang教程一(环境搭建,变量,数据类型,数组切片map),Golang,golang,开发语言,后端

  • 将go的对应bin目录设置为环境变量,这一步是方便可以在命令行里面直接使用go命令
  • 将go的第三方bin目录设置为环境变量,一般是在用户目录下,这一步是为了以后使用go install安装的第三方可执行文件可以直接使用

2.linux安装 

选择 xxx.linux-amd64.tar.gz

该站点比较快:All releases - The Go Programming Language

# 下载

wget https://golang.google.cn/dl/go1.22.2.linux-amd64.tar.gz

# 解压

tar -xvf go1.22.2.linux-arm64.tar.gz -C /usr/local

# 配置环境变量

echo 'export GO111MODULE=on' >> /etc/profile
echo 'export GOROOT=/usr/local/go' >> /etc/profile
echo 'export GOPATH=/home/gopath' >> /etc/profile
echo 'export PATH=$PATH:$GOROOT/bin:$GOPATH/bin' >> /etc/profile

source /etc/profile

# 创建go包安装目录

mkdir -p /home/gopath

# 设置代理

go env -w GOPROXY=https://goproxy.cn,direct

# 检查成功

go version

3.开发工具

推荐goland

二、变量定义与输入输出

1.变量定义

package main

import "fmt"

func main() {
  // 先定义,再赋值
  var name string
  name = "os_lee1"
  fmt.Println(name)
  
  // 定义加赋值
  var userName string = "os_lee1"
  fmt.Println(userName)
}

如果一个变量定义了,但是没有赋值,那么这个变量的值就是这个类型的 "零值" 

// 变量类型省略
var name = "os_lee"

// 简单声明
name := "os_lee"

2.全局变量与局部变量

定义在函数体(包括main函数)内的变量都是局部变量,定义了就必须使用
定义在外部的变量就是全局变量,可以只定义不使用 

package main

import "fmt"

// 全局变量可以不使用
var userName = "oslee_全局" 

func main() {
  // 局部变量
  var name = "oslee_局部"
  // 在函数体内定义的变量,必须要使用
  fmt.Println(name)
}

3.定义多个变量

package main

import "fmt"

func main() {
	var name1, name2, name3 string // 定义多个变量

	var a1, a2 = "os", "lee" // 定义多个变量并赋值

	a3, a4 := "os", "lee" // 简短定义多个变量并赋值

	fmt.Printf("name1: %s, name2: %s, name3: %s\n", name1, name2, name3)
	fmt.Printf("a1: %s, a2: %s, a3: %s, a4: %s\n", a1, a2, a3, a4)
}
package main

import "fmt"

var (
	name     string = "os"
	userName        = "os_lee"
)

func main() {
	fmt.Println(name, userName)
}

4.常量定义

定义的时候就要赋值
赋值之后就不能再修改了

package main

import "fmt"

const name string = "os_lee" // 定义就要赋值

func main() {
	fmt.Println(name)
}

5.命名规范

核心思想:首字母大写的变量、函数。方法,属性可在包外进行访问

6.输出

package main

import "fmt"

func main() {
	fmt.Println("os_lee")
	fmt.Println(1)
	fmt.Println(true)
	fmt.Println("什么", "都", "可以", "输出")
}

格式化输出

%v 按值的本来值输出
%+v 在 %v 基础上,对结构体字段名和值进行展开
%#v 输出 Go 语言语法格式的值
%T 输出 Go 语言语法格式的类型和值
%% 输出 % 本体
%b(oOdxX) 整型的不同进制方式显示
%U Unicode 字符
%s 字符串
%d 整数
%f 浮点数
%p 指针,十六进制方式显示
package main

import "fmt"

func main() {
    fmt.Printf("%v\n", "你好")           // 可以作为任何值的占位符输出
    fmt.Printf("%v %T\n", "os", "lee") // 打印类型
    fmt.Printf("%d\n", 3)              // 整数
    fmt.Printf("%.2f\n", 1.25)         // 小数
    fmt.Printf("%s\n", "哈哈哈")          // 字符串
    fmt.Printf("%#v\n", "")            // 用go的语法格式输出,很适合打印空字符串

    // 还有一个用的比较多的就是将格式化之后的内容赋值给一个变量
    name := fmt.Sprintf("%v", "你好")
    fmt.Println(name)
}

7.输入 

package main

import "fmt"

func main() {
	fmt.Println("输入您的名字:")
	var name string
	fmt.Scan(&name) // 这里记住,要在变量的前面加个&, 后面讲指针会提到
	fmt.Println("你输入的名字是", name)
}

三、基本数据类型

go语言的基本数据类型有

  1. 整数形
  2. 浮点型
  3. 复数
  4. 布尔
  5. 字符串

1.整数型

go语言的整数类型,具体细分有很多

var n1 uint8 = 2 
var n2 uint16 = 2 
var n3 uint32 = 2 
var n4 uint64 = 2 
var n5 uint = 2 
var n6 int8 = 2 
var n7 int16 = 2 
var n8 int32 = 2 
var n9 int64 = 2 
var n10 int = 2 

大家只需要记住以下几点

  1. 默认的数字定义类型是int类型
  2. 带个u就是无符号,只能存正整数
  3. 后面的数字就是2进制的位数
  4. uint8还有一个别名 byte, 一个字节=8个bit位
  5. int类型的大小取决于所使用的平台

例如uint8,那就是8个二进制位,都用来存储数据,那最小就是0,最大就是2的八次方-1=255

那int8,因为要拿一位存符合,使用实际只有七位可用,所以最小的就是负2的七次方=-128,最大的就是2的七次方-1=127

至于为什么要减一,其实很好理解,因为实际到最后一个数字的时候,已经向前进位了,例如一个小时是60分钟,但是分钟最大只有59

第五点的测试

我是64位操作系统,那么我会试一下int是不是就是int64的最大上限

2的63次方-1=9223372036854775807

fmt.Printf("%.0f\n", math.Pow(2, 63))
var n1 int = 9223372036854775807
fmt.Println(n1)
var n2 int = 9223372036854775808 // 看它报不报错
fmt.Println(n2)

2.浮点型

Go语言支持两种浮点型数:float32 和 float64

  • float32 的浮点数的最大范围约为3.4e38,可以使用常量定义:math.MaxFloat32
  • float64 的浮点数的最大范围约为 1.8e308,可以使用一个常量定义:math.MaxFloat64

如果没有显式声明,则默认是float64

3.字符型

注意哦,是字符,不是字符串

比较重要的两个类型是byte(单字节字符)和rune(多字节字符)

package main

import "fmt"

func main() {
	var c1 = 'a'
	var c2 = 97
	fmt.Println(c1) // 直接打印都是数字
	fmt.Println(c2)

	fmt.Printf("%c %c\n", c1, c2) // 以字符的格式打印

	var r1 rune = '中'
	fmt.Printf("%c\n", r1)
}

在 Go 中,字符的本质是一个整数,直接输出时,是该字符对应的 UTF-8 编码的码值
可以直接给某个变量赋一个数字,然后按格式化输出时 %c ,会输出该数字对应的 unicode 字符
字符类型是可以进行运算的,相当于一个整数,因为它都对应有 Unicode 码。

4.字符串类型

和字符不一样的是,字符的赋值是单引号,字符串的赋值是双引号 

var s string = "lee李"
fmt.Println(s)

转义字符

一些常用的转义字符

fmt.Println("os\tlee")             // 制表符
fmt.Println("os\nlee")             // 回车
fmt.Println("\"os\"lee")           // 双引号
fmt.Println("os\rlee")             // 回到行首
fmt.Println("C:\\pprof\\main.exe") // 反斜杠

其他的转义字符

" 双引号
\ 反斜线
\a 报警声
\b 退格
\f 换页
\n 换行
\r 回车替换
\v 垂直制表符
\t 制表符

多行字符串

在``这个里面,再出现转义字符就会原样输出了

package main

import "fmt"

func main() {
	str := `今天
天气
真好
`
	fmt.Println(str)
}

5.布尔类型

  • 布尔型数据只有 true(真)和 false(假)两个值
  • 布尔类型变量的默认值为false
  • Go 语言中不允许将整型强制转换为布尔型
  • 布尔型无法参与数值运算,也无法与其他类型进行转换
  • 零值问题
    如果我们给一个基本数据类型只声明不赋值,那么这个变量的值就是对应类型的零值,例如int就是0,bool就是false,字符串就是""

package main

import "fmt"

func main() {
	var a1 int
	var a2 float32
	var a3 string
	var a4 bool

	fmt.Printf("%#v\n", a1)
	fmt.Printf("%#v\n", a2)
	fmt.Printf("%#v\n", a3)
	fmt.Printf("%#v\n", a4)
}

四、数组、切片、map

1.数组

数组(Array)是一种非常常见的数据类型,几乎所有的计算机编程语言中都会用到它

  1. 数组里的元素必须全部为同一类型,要嘛全部是字符串,要嘛全部是整数
  2. 声明数组时,必须指定其长度或者大小
package main

import "fmt"

func main() {
	var array [3]int = [3]int{1, 2, 3}
	fmt.Println(array)
	var array1 = [3]int{1, 2, 3}
	fmt.Println(array1)
	var array2 = [...]int{1, 2, 3}
	fmt.Println(array2)
}

 如果要修改某个值,只能根据索引去找然后替换

var array1 = [3]int{1, 2, 3}
array1[0] = 10 // 根据索引找到对应的元素位置,然后替换
fmt.Println(array1)

 2.切片

很明显啊,go里面的数组,长度被限制死了,所以不经常用

所以go出了一个数组plus,叫做slice(切片)

切片(Slice)相较于数组更灵活,因为在声明切片后其长度是可变的

package main

import "fmt"

func main() {
  // 定义一个字符串切片
  var list []string

  list = append(list, "枫枫")
  list = append(list, "知道")
  fmt.Println(list)
  fmt.Println(len(list)) // 切片长度
  // 修改第二个元素
  list[1] = "不知道"
  fmt.Println(list)
}

make函数

除了基本数据类型,其他数据类型如果只定义不赋值,那么实际的值就是nil

// 定义一个字符串切片
var list []string
fmt.Println(list == nil) // true

那么我们可以通过make函数创建指定长度,指定容量的切片了

make([]type, length, capacity)
package main

import "fmt"

func main() {
	// 定义一个字符串切片
	var list = make([]string, 0)
	fmt.Println(list, len(list), cap(list))
	fmt.Println(list == nil) // false

	list1 := make([]int, 2, 2)
	fmt.Println(list1, len(list1), cap(list1))
}

为什么叫切片?
因为切片是数组切出来的

package main

import "fmt"

func main() {
	var list = [...]string{"a", "b", "c"}
	slices := list[:] // 左一刀,右一刀 变成了切片
	fmt.Println(slices)
	fmt.Println(list[1:2]) // b
}

切片排序

package main

import (
	"fmt"
	"sort"
)

func main() {
	var list = []int{4, 5, 3, 2, 7}
	fmt.Println("排序前:", list)
	sort.Ints(list)
	fmt.Println("升序:", list)
	sort.Sort(sort.Reverse(sort.IntSlice(list)))
	fmt.Println("降序:", list)
}

切片面试题 

面试题1:什么是Go语言中的切片?

答案: Go语言中的切片(slices)是一种灵活的、动态大小的、基于数组的抽象数据类型。它并不存储任何数据,而是指向底层数组的一个片段,包含了三个信息:指向数组的指针、长度(len)和容量(cap)。长度表示切片当前拥有的元素个数,容量则是切片可以扩展到的最大元素个数,容量等于或大于长度。

面试题2:切片的扩容是如何工作的?

答案: 当向切片添加元素超出其当前容量时,Go语言会自动扩容切片。扩容的具体策略并不是固定的,但大致遵循以下规则:

  • 如果切片的容量不足以容纳新增元素,Go 会创建一个新的更大的底层数组,将原有数据复制到新数组,并更新切片的指针和容量。
  • 扩容因子通常为原来容量的2倍,但是也可能会根据实际情况调整,比如在Go 1.17版本之后,根据内存分配器的行为,扩容可能会跳跃式增长以更好地适应内存分配器的粒度。
  • 新容量至少会增加到原来的两倍+所需添加的元素数量,以尽量减少频繁的扩容操作。

面试题3:切片与数组有什么区别?

答案

  1. 长度可变性

    • 数组(array)的长度在声明时确定并且不能改变。
    • 切片(slice)虽然在声明时可以指定初始长度,但可以在运行时动态改变其长度(增删元素),不过容量有限制。
  2. 存储结构

    • 数组是一个定长的、连续的内存区域。
    • 切片不是数据结构,它只是一个描述符,指向一个数组的一部分。
  3. 引用行为

    • 数组变量直接存储数据,赋值操作会复制整个数组的内容。
    • 切片变量存储的是指向数组的指针和长度、容量信息,赋值操作只会复制切片描述符,不会复制底层数据。

面试题4:浅拷贝和深拷贝

浅拷贝(Shallow Copy): 浅拷贝是创建一个新的切片,但它仍然指向同一个底层数组。这意味着对新切片所做的修改会影响到原始切片所指向的数据。

// 示例1:直接赋值
original := []int{1, 2, 3}
copied := original // 此时copied是对original的浅拷贝

// 示例2:使用内置的copy函数
original := []int{1, 2, 3}
copied := make([]int, len(original))
copy(copied, original) // 这也是浅拷贝,copied和original共享相同的底层数组

深拷贝(Deep Copy): 深拷贝是创建一个与原始切片完全独立的新切片,包含一个全新的底层数组。对新切片所做的修改不会影响到原始切片。

// 手动循环遍历复制每一个元素
original := []int{1, 2, 3}
copied := make([]int, len(original))
for i, v := range original {
copied[i] = v
}

// 或者使用反射(reflect)包,但请注意这不是最优实践,仅作演示
import "reflect"
original := []int{1, 2, 3}
copied := reflect.ValueOf(original).Clone().Interface().([]int)

3.Map

  1. Go语言中的map(映射、字典)是一种内置的数据结构,它是一个无序的key-value对的集合
  2. map的key必须是基本数据类型,value可以是任意类型
  3. 注意,map使用之前一定要初始化
package main

import "fmt"

func main() {
	// 声明
	var m1 map[string]string
	// 初始化1
	m1 = make(map[string]string)
	// 初始化2
	m1 = map[string]string{}
	// 设置值
	m1["name"] = "枫枫"
	fmt.Println(m1)
	// 取值
	fmt.Println(m1["name"])
	// 删除值
	delete(m1, "name")
	fmt.Println(m1)

	// 声明并赋值
	var m2 = map[string]string{}
	fmt.Println(m2)
	var m3 = make(map[string]string)
	fmt.Println(m3)

}

map取值

  1. 如果只有一个参数接,那这个参数就是值,如果没有,这个值就是类型的零值
  2. 如果两个参数接,那第二个参数就是布尔值,表示是否有这个元素
package main

import "fmt"

func main() {
	// 声明并赋值
	var m1 = map[string]int{
		"age": 21,
	}
	age1 := m1["age1"] // 取一个不存在的
	fmt.Println(age1)
	age2, ok := m1["age1"]
	fmt.Println(age2, ok)
}

map面试题 

面试题1:什么是Go语言中的map?

答案: Go语言中的map是一种关联数组或字典类型的数据结构,它存储键值对(key-value pairs),通过键(key)快速查找对应的值(value)。键和值可以是任何类型,但键的类型必须支持相等比较,通常为整型、浮点型、字符串或复合类型(如结构体,但结构体内的字段必须支持相等比较)。

面试题2:Go语言中的map何时会引发panic?

答案

  • 在使用尚未初始化的map时(即nil map)执行读写操作,会导致panic。
  • 在迭代map的过程中,如果同时修改该map,也会导致panic,除非使用for range循环迭代并在循环体内使用delete函数删除元素。

面试题3:Go语言中map的扩容是如何进行的?

Go语言中的map在底层实现上使用了哈希表。当map中的元素数量越来越多,达到一定的负载因子时,Go语言会自动触发map的扩容操作。扩容是为了保持map操作的高效性,防止哈希冲突过于密集,导致性能下降。

扩容的具体流程如下:

  1. 负载因子判断: 当map的元素数量(entry count)与其桶(bucket)数量的比例超过一定阈值时(通常大约是6.5),map会触发扩容。这个阈值可以通过runtime包的内部常量mapExpandHeapSizemapExpandLoadFactor间接推算出来。

  2. 新桶分配: 扩容时,Go会创建一个新的、大小翻倍的哈希表。例如,如果原map的桶数量是2^N,则新表的桶数量将是2^(N+1)。

  3. 元素迁移: Go采用了渐进式(incremental)的迁移策略,不会一次性将所有元素从旧表迁移到新表。在每次map的读写操作时,如果发现正在进行扩容操作,就会顺带将旧表中的部分元素迁移到新表中。每次操作最多迁移两个桶(bucket)的数据。

  4. 保持引用关系: 在扩容过程中,map的旧表和新表会同时存在,直到所有元素都迁移到新表为止。旧表的最后一个桶会存储一个指向新表的指针,以确保在扩容过程中依然能正确找到已迁移的元素。

  5. 空间回收: 所有元素都迁移到新表后,旧表的空间最终会被垃圾回收机制释放。

值得注意的是,上述细节基于Go语言的早期版本,Go语言的map扩容机制在不同版本间可能会有所调整。最新的Go版本可能会根据具体情况采用不同的扩容策略和负载因子阈值。文章来源地址https://www.toymoban.com/news/detail-853476.html

到了这里,关于Golang教程一(环境搭建,变量,数据类型,数组切片map)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Golang】Golang进阶系列教程--Go 语言切片是如何扩容的?

    在 Go 语言中,有一个很常用的数据结构,那就是切片(Slice)。 切片是一个拥有相同类型元素的可变长度的序列,它是基于数组类型做的一层封装。它非常灵活,支持自动扩容。 切片是一种引用类型,它有三个属性:指针,长度和容量。 底层源码定义如下: 指针: 指向

    2024年02月14日
    浏览(70)
  • C语言入门教程,C语言学习教程(第三部分:C语言变量和数据类型)二

    前面我们多次提到了字符串,字符串是多个字符的集合,它们由 \\\" \\\" 包围,例如 \\\"http://c.biancheng.net\\\" 、 \\\"C语言中文网\\\" 。字符串中的字符在内存中按照次序、紧挨着排列,整个字符串占用一块连续的内存。 当然,字符串也可以只包含一个字符,例如 \\\"A\\\" 、 \\\"6\\\" ;不过为了操作方

    2024年01月17日
    浏览(51)
  • 【python基础】复杂数据类型-列表类型(列表切片)

    视频讲解 前面学习的是如何处理列表的 所有数据元素 。Python还可以处理列表的部分元素,Python称之为切片。 创建切片,可指定要使用的第一个数据元素的索引和最后一个数据元素的索引。与range函数一样,Python在到达指定的第二个索引 前面的 数据元素后停止。比如要切片

    2024年02月07日
    浏览(52)
  • Mac golang下载安装以及环境变量配置

    下载地址: All releases - The Go Programming Language

    2024年02月19日
    浏览(60)
  • Python中二维数据(数组、列表)索引和切片的Bug

    对于一维数据进行索引和切片操作,大家都比较熟悉通过下面代码进行实现 对于一维列表元组等相关结果的索引和切片操作,与一维数组类似 对于二维数据的索引和切片就有一些需要注意的事项了,如果一不小心可能会出现意料之外的Bug 上面就是二维数组索引和切片的大部

    2024年01月20日
    浏览(48)
  • 【Golang入门教程】Go语言变量的初始化

    强烈推荐 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站: 人工智能 推荐一个个人工作,日常中比较常用的人工智能工具,无需魔法,忍不住分享一下给大家。点击跳转到网站: 人工智能工具 引言 在Go语言中,变量

    2024年04月17日
    浏览(78)
  • Go 工具链详解(四): Golang环境变量设置和查看工具 go env

    go env 是 Go 工具链中的一个命令,用于设置和查看当前 Golang 环境的相关信息,对于理解、编译和运行 Golang 程序非常有用。 go 提供的命令及 go 程序的编译运行都会使用到环境变量,如果未设置对应的环境变量,go 则会使用其默认设置。默认情况下,env 以 shell 脚本(在Windo

    2024年02月16日
    浏览(42)
  • golang环境搭建

    写入以下信息:

    2024年02月12日
    浏览(31)
  • 搭建golang开发环境

    这里参考一篇文章: golang环境变量链接,还不错

    2024年02月15日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包