当前位置: 首页 > 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>…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

TDengine 快速体验(Docker 镜像方式)

简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能&#xff0c;本节首先介绍如何通过 Docker 快速体验 TDengine&#xff0c;然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker&#xff0c;请使用 安装包的方式快…...

利用ngx_stream_return_module构建简易 TCP/UDP 响应网关

一、模块概述 ngx_stream_return_module 提供了一个极简的指令&#xff1a; return <value>;在收到客户端连接后&#xff0c;立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量&#xff08;如 $time_iso8601、$remote_addr 等&#xff09;&a…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

Robots.txt 文件

什么是robots.txt&#xff1f; robots.txt 是一个位于网站根目录下的文本文件&#xff08;如&#xff1a;https://example.com/robots.txt&#xff09;&#xff0c;它用于指导网络爬虫&#xff08;如搜索引擎的蜘蛛程序&#xff09;如何抓取该网站的内容。这个文件遵循 Robots…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中&#xff0c;性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期&#xff0c;开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发&#xff0c;但背后往往隐藏着系统资源调度不当…...

JavaScript 数据类型详解

JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型&#xff08;Primitive&#xff09; 和 对象类型&#xff08;Object&#xff09; 两大类&#xff0c;共 8 种&#xff08;ES11&#xff09;&#xff1a; 一、原始类型&#xff08;7种&#xff09; 1. undefined 定…...

接口自动化测试:HttpRunner基础

相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具&#xff0c;支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议&#xff0c;涵盖接口测试、性能测试、数字体验监测等测试类型…...