当前位置: 首页 > news >正文

GO语言学习笔记(与Java的比较学习)(四)

结构体

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

package main
​
import "fmt"
​
type Vertex struct {X intY int
}
​
func main() {fmt.Println(Vertex{1, 2})
}

结构体中的字段用 . 访问

package main
​
import "fmt"
​
type Vertex struct {X intY int
}
​
func main() {v := Vertex{1, 2}v.X = 4fmt.Println(v.X)
}

结构体指针

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

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

package main
​
import "fmt"
​
type Vertex struct {X intY int
}
​
func main() {v := Vertex{1, 2}p := &vp.X = 1e9fmt.Println(v)
}

结构体文法

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

使用 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:0p  = &Vertex{1, 2} // 创建一个 *Vertex 类型的结构体(指针)
)
​
func main() {fmt.Println(v1, p, v2, v3)
}

数组与切片

数组声明和初始化

数组是具有相同 唯一类型 的一组以编号且长度固定的数据项序列。

注意事项

  • 如果我们想让数组元素类型为任意类型的话可以使用空接口作为类型,当使用值时我们必须先做一个类型判断。

  • 数组长度最大为 2Gb

声明格式:

var identifier [len]type

Go 语言中的数组是一种 值类型(不像 C/C++ 中是指向首元素的指针),所以可以通过 new() 来创建: var arr1 = new([5]int)。

提出问题:这种方式和 var arr2 [5]int 的区别是什么呢?arr1 的类型是 *[5]int,而 arr2 的类型是 [5]int

数组常量

如果数组值已经提前知道了,那么可以通过 数组常量 的方法来初始化数组,而不用依次使用 []= 方法(所有的组成元素都有相同的常量语法)。

package main
import "fmt"
​
func main() {// var arrAge = [5]int{18, 20, 15, 22, 16}// var arrLazy = [...]int{5, 6, 7, 8, 22}// var arrLazy = []int{5, 6, 7, 8, 22}var arrKeyValue = [5]string{3: "Chris", 4: "Ron"}// var arrKeyValue = []string{3: "Chris", 4: "Ron"}
​for i:=0; i < len(arrKeyValue); i++ {fmt.Printf("Person at %d is %s\n", i, arrKeyValue[i])}
}

多维数组

数组通常是一维的,但是可以用来组装成多维数组,例如:[3][5]int[2][2][2]float64

内部数组总是长度相同的。Go 语言的多维数组是矩形式的

将数组传递给函数

把一个大数组传递给函数会消耗很多内存。有两种方法可以避免这种现象:

  • 传递数组的指针

  • 使用数组的切片

package main
import "fmt"
​
func main() {array := [3]float64{7.0, 8.5, 9.1}x := Sum(&array) // Note the explicit address-of operator// to pass a pointer to the arrayfmt.Printf("The sum of the array is: %f", x)
}
​
func Sum(a *[3]float64) (sum float64) {for _, v := range *a { // derefencing *a to get back to the array is not necessary!sum += v}return
}

切片

概念

  • 切片(slice)是对数组一个连续片段的引用(该数组我们称之为相关数组,通常是匿名的),所以切片是一个引用类型(因此更类似于 C/C++ 中的数组类型,或者 Python 中的 list 类型)。这个片段可以是整个数组,或者是由起始和终止索引标识的一些项的子集。需要注意的是,终止索引标识的项不包括在切片内。切片提供了一个相关数组的动态窗口。

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

  • 切片是可索引的,并且可以由 len() 函数获取长度。

  • 和数组不同的是,切片的长度可以在运行时修改,最小为 0 最大为相关数组的长度:切片是一个 长度可变的数组

  • 切片提供了计算容量的函数 cap() 可以测量切片最长可以达到多少:它等于切片从第一个元素开始,到相关数组末尾的元素个数。

  • 切片的长度永远不会超过它的容量,所以对于 切片 s 来说该不等式永远成立:0 <= len(s) <= cap(s)

  • 多个切片如果表示同一个数组的片段,它们可以共享数据;因此一个切片和相关数组的其他切片是共享存储的,相反,不同的数组总是代表不同的存储。数组实际上是切片的构建块

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

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

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 intb bool}{{2, true},{3, false},{5, true},{7, true},{11, false},{13, true},}fmt.Println(s)
}

声明切片的格式是var identifier []type(不需要说明长度)。

一个切片在未初始化之前默认为 nil,长度为 0。

切片的初始化格式是:var slice1 []type = arr1[start:end]。(这表示 slice1 是由数组 arr1 从 start 索引到 end-1 索引之间的元素构成的子集(切分数组,start:end 被称为 slice 表达式)。所以 slice1[0] 就等于 arr1[start]。)

注意:

  • 如果某个人写:var slice1 []type = arr1[:] 那么 slice1 就等于完整的 arr1 数组(所以这种表示方式是 arr1[0:len(arr1)] 的一种缩写)。另外一种表述方式是:slice1 = &arr1。

  • 如果 s2 是一个 slice,你可以将 s2 向后移动一位 s2 = s2[1:],但是末尾没有移动。切片只能向后移动,s2 = s2[-1:] 会导致编译错误。切片不能被重新分片以获取数组的前一个元素。

用 make () 创建一个切片

当相关数组还没有定义时,我们可以使用 make () 函数来创建一个切片 同时创建好相关数组:var slice1 []type = make([]type, len)。也可以简写为 slice1 := make([]type, len),这里 len 是数组的长度并且也是 slice 的初始长度。

new () 和 make () 的区别

看起来二者没有什么区别,都在堆上分配内存,但是它们的行为不同,适用于不同的类型。

  • new (T) 为每个新的类型 T 分配一片内存,初始化为 0 并且返回类型为 * T 的内存地址:这种方法 返回一个指向类型为 T,值为 0 的地址的指针,它适用于值类型如数组和结构体;它相当于 &T{}。

  • make(T) 返回一个类型为 T 的初始值,它只适用于 3 种内建的引用类型:切片、map 和 channel

多维 切片

和数组一样,切片通常也是一维的,但是也可以由一维组合成高维。通过分片的分片(或者切片的数组),长度可以任意动态变化,所以 Go 语言的多维切片可以任意切分。而且,内层的切片必须单独分配(通过 make 函数)。

bytes 包

类型 []byte 的切片十分常见,Go 语言有一个 bytes 包专门用来解决这种类型的操作方法。

bytes 包和字符串包十分类似(参见第 4.7 节)。而且它还包含一个十分有用的类型 Buffer:

import "bytes"
​
type Buffer struct {...
}

Buffer 可以这样定义:

var buffer bytes.Buffer

或者使用 new 获得一个指针:

var r *bytes.Buffer = new(bytes.Buffer)

或者通过函数:func NewBuffer(buf []byte) *Buffer,创建一个 Buffer 对象并且用 buf 初始化好;NewBuffer 最好用在从 buf 读取的时候使用。

通过 buffer 串联字符串

类似于 Java 的 StringBuilder 类。

var buffer bytes.Buffer
for {if s, ok := getNextString(); ok { //method getNextString() not shown herebuffer.WriteString(s)} else {break}
}
fmt.Print(buffer.String(), "\n")

切片重组

我们已经知道切片创建的时候通常比相关数组小,例如:

slice1 := make([]type, start_length, capacity)

其中 start_length 作为切片初始长度而 capacity 作为相关数组的长度。

这么做的好处是我们的切片在达到容量上限后可以扩容。改变切片长度的过程称之为切片重组 reslicing,做法如下:

slice1 = slice1[0:end]

,其中 end 是新的末尾索引(即长度)。

切片的复制与追加

如果想增加切片的容量,我们必须创建一个新的更大的切片并把原分片的内容都拷贝过来。

package main
import "fmt"
​
func main() {sl_from := []int{1, 2, 3}sl_to := make([]int, 10)
​n := copy(sl_to, sl_from)fmt.Println(sl_to)fmt.Printf("Copied %d elements\n", n) // n == 3
​sl3 := []int{1, 2, 3}sl3 = append(sl3, 4, 5, 6)fmt.Println(sl3)
}

如果使用append函数超过了切片的容量会怎样?

答:

  • 当使用 append 函数向切片添加元素时,如果超过了切片的容量,切片将会重新分配更大的内存空间,并将原来的元素复制到新的内存空间中。这意味着切片的长度和容量会增加,并且原来的元素会被复制到新的内存位置上。

  • 具体来说,如果切片的容量不足以容纳新的元素,则 append 函数会创建一个新的底层数组,并将原来的元素复制到这个新数组中。然后,新的元素会被添加到新的底层数组中,并返回一个指向新数组的切片。

  • 这也意味着如果你有一个指向原切片的指针,在调用 append 后,原切片可能会指向一个不同的内存地址,因为底层数组已经改变了。

学习参考资料:

《Go 入门指南》 | Go 技术论坛 (learnku.com)

Go 语言之旅

相关文章:

GO语言学习笔记(与Java的比较学习)(四)

结构体 一个结构体&#xff08;struct&#xff09;就是一组字段&#xff08;field&#xff09;。 package main ​ import "fmt" ​ type Vertex struct {X intY int } ​ func main() {fmt.Println(Vertex{1, 2}) } 结构体中的字段用 . 访问 package main ​ im…...

在实训云平台上配置云主机

文章目录 零、学习目标一、实训云升级二、实训云登录&#xff08;一&#xff09;登录实训云&#xff08;二&#xff09;切换界面语言&#xff08;三&#xff09;规划云主机实例 三、创建网络三、创建路由器2024-2-29更新到此四、添加接口五、创建端口六、添加安全组规则七、创建…...

什么是隔离式栅极驱动器?

在电子设备领域&#xff0c;“驱动”一词占据着至关重要的地位&#xff0c;充当推动信号、控制和电源的力量。这个复杂世界中的一个重要组件是隔离式栅极驱动器&#xff0c;这项技术在确保各种电子系统高效、安全运行方面发挥着关键作用。 什么是栅极驱动器&#xff1f; 从本质…...

蓝桥杯算法赛 第 6 场 小白入门赛 解题报告 | 珂学家 | 简单场 + 元宵节日快乐

前言 整体评价 因为适逢元宵节&#xff0c;所以这场以娱乐为主。 A. 元宵节快乐 题型: 签到 节日快乐&#xff0c;出题人也说出来自己的心愿, 祝大家AK快乐! import java.util.Scanner;public class Main {public static void main(String[] args) {System.out.println(&qu…...

附加Numpy数组

参考&#xff1a;Append Numpy Array 引言 在数据科学和机器学习领域&#xff0c;处理大规模数据集是一项重要且常见的任务。为了高效地处理数据&#xff0c;numpy是一个非常强大的Python库。本文将详细介绍numpy中的一个重要操作&#xff0c;即如何附加&#xff08;append&a…...

收银系统源码-智慧新零售,ERP进销存功能详解

智慧新零售是一套线下线上一体化的收银系统&#xff0c;不仅给门店线下提供了多样化的收款方式&#xff0c;还提供了和线下深度打通的线上小程序商城。有线下又有线上自然需要一套完整的进销存模块能高效的管理商品。 智慧新零售进销存功能涵盖了商品的采购、销售、调拨、盘点…...

STM32使用PB3, PB4引脚的注意事项

STM32的PB3, PB4引脚作为GPIO引脚需要注意&#xff0c;因为他们默认分别是JTDO和NJTRST引脚。 笔者在设计可调增益增益放大器&#xff08;VGA&#xff09;的时候&#xff0c;使用4个GPIO读取外部控制电压&#xff0c;根据约定的编码格式设定DAC的输出电压&#xff0c;从而设置V…...

OSCP靶场--DVR4

OSCP靶场–DVR4 考点(1.windows&#xff1a;路径遍历获取私钥getshell 2.ssh shell中runas切换用户) 1.nmap扫描 ┌──(root㉿kali)-[~/Desktop] └─# nmap -sV -sC -p- 192.168.161.179 --min-rate 2000 Starting Nmap 7.92 ( https://nmap.org ) at 2024-02-29 07:14 EST…...

【嵌入式——QT】日期与定时器

日期 QTime&#xff1a;时间数据类型&#xff0c;仅表示时间&#xff0c;如 16:16:16&#xff1b;QDate&#xff1a;日期数据类型&#xff0c;仅表示日期&#xff0c;如2024-1-22&#xff1b;QDateTime&#xff1a;日期时间数据类型&#xff0c;表示日期和时间&#xff0c;如2…...

如何决定使用HashMap还是TreeMap?

使用 HashMap 还是 TreeMap 取决于你的需求和对数据结构的理解。 HashMap&#xff1a; 快速插入和查找&#xff1a;HashMap 提供了常数时间&#xff08;O(1)&#xff09;的插入和查找操作&#xff0c;因此对于需要快速插入和查找的场景非常适用。无序性&#xff1a;HashMap 不保…...

平台工程与安全

平台工程不是为了取代DevOps&#xff0c;而是DevOps的进一步演进和发展。本文介绍了DevOps和平台工程&#xff0c;以及对于安全的意义。原文: Platform Engineering and Security: A Very Short Introduction 中国云南大理的日落 我是一名 DevOps 工程师&#xff0c;个人还是希…...

智能咖啡厅助手:人形机器人 +融合大模型,行为驱动的智能咖啡厅机器人(机器人大模型与具身智能挑战赛)

智能咖啡厅助手&#xff1a;人形机器人 融合大模型&#xff0c;行为驱动的智能咖啡厅机器人(机器人大模型与具身智能挑战赛) “机器人大模型与具身智能挑战赛”的参赛作品。的目标是结合前沿的大模型技术和具身智能技术&#xff0c;开发能在模拟的咖啡厅场景中承担服务员角色并…...

js处理IOS虚拟键盘弹出后输入框被遮住

​ JS IOS 前言 在项目开发的过程中&#xff0c;在IOS手机端系统下&#xff0c;当对输入框&#xff08;input/textarea&#xff09;进行focus操作时&#xff0c;键盘弹起遮住输入框。 问题描述 从页面底部focus输入框失败从页面中间focus输入框失败 原因 造成上述问题的&…...

脚手架工程使用ElementUI

在终端中执行以下指令 npm install --save element-ui 在终端中显示added 9 packages in 10s 说明安装完成 在工程的main.js中 导入并使用ElementUI: import ElementUI from element-ui import element-ui/lib/theme-chalk/index.css Vue.use(ElementUI) 可以在*.vue页面中…...

163邮箱SMTP端口号及服务器地址详细设置?

163邮箱SMTP端口号是什么&#xff1f;163邮件SMTP设置教程&#xff1f; 除了基本的邮箱账号和密码外&#xff0c;还需要了解SMTP服务器地址和端口号&#xff0c;以及相应的设置。这些设置对于确保邮件能够顺利发送至关重要。下面&#xff0c;蜂邮EDM将详细介绍163邮箱SMTP端口…...

【STM32】STM32学习笔记-独立看门狗和窗口看门狗(47)

00. 目录 文章目录 00. 目录01. WDG概述02. 独立看门狗相关API2.1 IWDG_WriteAccessCmd2.2 IWDG_SetPrescaler2.3 IWDG_SetReload2.4 IWDG_ReloadCounter2.5 IWDG_Enable2.6 IWDG_GetFlagStatus2.7 RCC_GetFlagStatus 03. 独立看门狗接线图04. 独立看门狗程序示例105. 独立看门…...

计算机网络——IPV4数字报

1. IPv4数据报的结构 本结构遵循的是RFC 791规范&#xff0c;介绍了一个IPv4数据包头部的不同字段。 1.1 IPv4头部 a. 版本&#xff08;Version&#xff09;&#xff1a;指明了IP协议的版本&#xff0c;IPv4表示为4。 b. 头部长度&#xff08;IHL, Internet Header Length&…...

java抽象方法和抽象类

1、抽象方法 如果父类的方法本身不需要实现任何功能&#xff0c;仅仅是为了定义方法签名&#xff0c;目的是让子类去覆盖它&#xff0c;那么&#xff0c;可以把父类的方法声明为抽象方法。 class Person { // 定义抽象方法public abstract void run(); } 把一个方法声明为a…...

echarts鼠标向右/向左绘制实现放大/还原

echarts toolbox 的datazoom提供了绘制放大的功能&#xff0c;但通过鼠标绘制只能进行放大 应需求放大与还原都通过鼠标行为实现&#xff0c;增加从右往左绘制时还原放大结果 demo 结果 重写datazoom的原型方法实现绘制事件的拦截 const comp myChart._model.getComponent(to…...

Go编译DLL与SO

1. 简介 将Go编译成DLL/SO供其他语言调用。 .DLL&#xff1a;文件是 Windows 操作系统的动态链接库文件。.SO 文件是 Unix、Linux 和其他类 Unix 系统的共享库文件。 2. Go编译DLL/SO 注意 export后面导出的方法名一定要大写。 package main/* #include <stdlib.h>…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

前端开发面试题总结-JavaScript篇(一)

文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包&#xff08;Closure&#xff09;&#xff1f;闭包有什么应用场景和潜在问题&#xff1f;2.解释 JavaScript 的作用域链&#xff08;Scope Chain&#xff09; 二、原型与继承3.原型链是什么&#xff1f;如何实现继承&a…...

Razor编程中@Html的方法使用大全

文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...

为什么要创建 Vue 实例

核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...

windows系统MySQL安装文档

概览&#xff1a;本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容&#xff0c;为学习者提供全面的操作指导。关键要点包括&#xff1a; 解压 &#xff1a;下载完成后解压压缩包&#xff0c;得到MySQL 8.…...

第八部分:阶段项目 6:构建 React 前端应用

现在&#xff0c;是时候将你学到的 React 基础知识付诸实践&#xff0c;构建一个简单的前端应用来模拟与后端 API 的交互了。在这个阶段&#xff0c;你可以先使用模拟数据&#xff0c;或者如果你的后端 API&#xff08;阶段项目 5&#xff09;已经搭建好&#xff0c;可以直接连…...

webpack面试题

面试题&#xff1a;webpack介绍和简单使用 一、webpack&#xff08;模块化打包工具&#xff09;1. webpack是把项目当作一个整体&#xff0c;通过给定的一个主文件&#xff0c;webpack将从这个主文件开始找到你项目当中的所有依赖文件&#xff0c;使用loaders来处理它们&#x…...

DAY 45 超大力王爱学Python

来自超大力王的友情提示&#xff1a;在用tensordoard的时候一定一定要用绝对位置&#xff0c;例如&#xff1a;tensorboard --logdir"D:\代码\archive (1)\runs\cifar10_mlp_experiment_2" 不然读取不了数据 知识点回顾&#xff1a; tensorboard的发展历史和原理tens…...

路由基础-路由表

本篇将会向读者介绍路由的基本概念。 前言 在一个典型的数据通信网络中&#xff0c;往往存在多个不同的IP网段&#xff0c;数据在不同的IP网段之间交互是需要借助三层设备的&#xff0c;这些设备具备路由能力&#xff0c;能够实现数据的跨网段转发。 路由是数据通信网络中最基…...