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 语言之旅

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

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

相关文章

【GB28181】wvp-GB28181-pro快速适配 连接SQlite3数据库

引言 wvp最新项目支持mysql等数据库, 如果本地没有安装mysql等数据库,并想直接可以运行wvp项目,需要进行二次修改。 本文包含:WVP最新代码适配SQlite3数据库 运行平台:windows或linux 文章目录 一、为何使用SQlite二、配置修改2.1 添加SQlite3依赖2.2 修改SQlite3不支持的…

进程的通信以及信号的学习

一&#xff0c;进程的通信&#xff1a; 种类&#xff1a;1.管道 2.信号 3.消息队列 4.共享内存 5.信号灯 6.套接字 1.管道: 1.无名管道 无名管道只能用于具有亲缘关系的进程间通信 pipe int pipe(int pipefd[2]); 功能: 创建一个无名管道 …

Rust 交叉编译 macOS 为 Linux 和 Windows

文章目录 前言环境案例macOS 编译为 Linux 和 Windows 可用二进制程序编译为 Linux 平台编译为Windows平台 最后 前言 鉴于 rust 中文资料较少&#xff0c;遇到问题的解决方案更少。这里记录遇到的一些问题。 Rust 支持交叉编译&#xff0c;可以在 macOS 平台编译出 Linux 或者…

机器学习——CBOW基于矩阵(手动实操)

基于矩阵的CBOW基础算法&#xff0c;其实是负采样的前提算法。 主要是根据 预测准确率为22%左右 说实话。。。我已经很满意了&#xff0c;至少这个东西是可以去预测的&#xff0c;至于预测为什么不正确&#xff0c;我目前猜测主要还是跟词频有关。 在结果中&#xff0c;an…

uniapp:启动图 .9png 制作教程

1、工具安装&#xff1a;自行下载Android Studio 2、制作.9png 注意上图3条黑线的位置&#xff0c;意思是&#xff1a;标注黑线的位置可以进行缩放。 对其大多数启动图来说&#xff0c;标注以上3条黑线即可。

一周掌握【机器学习】入门知识

学习目标&#xff1a; 一周掌握 机器学习 入门知识 学习内容&#xff1a; 1.了解机器学习的基本概念&#xff1a; 阅读由 Keras 的创建者 Francois Chollet 编著的《使用 Python进行深度学习》。这本书从程序员的角度介绍了机器学习的基础知识。您可以阅读第 1-4 章&#xff…

ETH开源PPO算法学习

前言 项目地址&#xff1a;https://github.com/leggedrobotics/rsl_rl 项目简介&#xff1a;快速简单的强化学习算法实现&#xff0c;设计为完全在 GPU 上运行。这段代码是 NVIDIA Isaac GYM 提供的 rl-pytorch 的进化版。 下载源码&#xff0c;查看目录&#xff0c;整个项目…

创新之巅 健康之选 森歌集成灶智能水洗新揭秘

2024年2月27日&#xff0c;一场引领智能厨电风潮的盛会在杭州隆重召开。森歌集成灶以“勠力同心 共生共歌”为主题&#xff0c;成功举办了2024森歌智能厨电优秀经销商峰会。此次峰会上&#xff0c;森歌集成灶发布了令人瞩目的奥运冠军同款智能厨电新品——森歌鲸洗小灶Z60&…

前端架构: 脚手架之多package项目管理和架构

多package项目管理 1 &#xff09;多package项目管理概述 通常来说&#xff0c;当一个项目变大了以后&#xff0c;我们就要对这个项目进行拆分在前端当中&#xff0c;对于项目进行拆分的方式&#xff0c;通常把它称之为javascript包管理需要使用一个工具叫做 npm (Node Packag…

JS二进制文件转换:File、Blob、Base64、ArrayBuffer

类型转换 1. Blob、File → Base64 function fileToDataURL(file) {let reader new FileReader();reader.readAsDataURL(file);reader.onload function (e) {return reader.result;}; }2. Base64 → Blob、File // Base64 转为 Blob function dataURLToBlob(fileDataURL) …

【服务器磁盘清理技巧】

服务器磁盘空间的管理是一个非常重要的系统管理员工作。大量的日志文件、临时文件、备份文件等可能会迅速填满你的磁盘空间&#xff0c;导致应用无法正常运行。因此&#xff0c;磁盘空间的清理和管理就显得非常重要。 本文将介绍一些在Linux服务器上清理磁盘空间的基本技巧。 …

Java开发的核心模式 - MVC

文章目录 1、MVC设计模式2、Web开发本质3、服务器的性能瓶颈 1、MVC设计模式 MVC设计模式示意图 在整个Java学习之旅中&#xff0c;MVC&#xff08;Model-View-Controller&#xff09;设计模式无疑占据着极其重要的地位&#xff0c;堪称理解和掌握Java项目开发精髓的钥匙。如…

Python Pandas处理金额注意事项和案例

使用 Python 的 Pandas 库处理金额时&#xff0c;有几个注意事项可以帮助确保准确性和避免常见的问题&#xff1a; 注意事项 使用适当的数据类型: 金额通常应该使用定点数来表示&#xff0c;以避免浮点数运算中的舍入误差。可以使用 decimal.Decimal 类型来保持高精度。 避免…

IP源防攻击IPSG(IP Source Guard)

IP源防攻击IPSG&#xff08;IP Source Guard&#xff09;是一种基于二层接口的源IP地址过滤技术&#xff0c;它能够防止恶意主机伪造合法主机的IP地址来仿冒合法主机&#xff0c;还能确保非授权主机不能通过自己指定IP地址的方式来访问网络或攻击网络。 2.1 IPSG基本原理 绑定…

关于delphi6提示[Fatal Error] File not found: ‘System.pas‘

关于delphi6提示[Fatal Error] File not found: System.pas 一、[Fatal Error] File not found: System.pas的原因 1、System.dcu的输出没有覆盖项目引用路径..\..\dcu下 2、注意事项&#xff1a;System.pas等源码不能赋值到..\..\dcu 3、下述控件的Tools-Environment Optio…

android嵌入式开发及实训答案,android面试简历模板

前言 本想今年辞掉工作大干一场&#xff0c;没想到碰到疫情&#xff0c;家里蹲了3个月…&#xff0c;还好字节能给一次机会。前阵子字节跳动的提前批开始了&#xff0c;看宣传是说有海量HC&#xff0c;机会多多&#xff0c;本着涨涨面经的心理&#xff0c;然后就投递了一下杭州…

如何利用ChatGPT搞科研?论文检索、写作、基金润色、数据分析、科研绘图(全球地图、植被图、箱型图、雷达图、玫瑰图、气泡图、森林图等)

以ChatGPT、LLaMA、Gemini、DALLE、Midjourney、Stable Diffusion、星火大模型、文心一言、千问为代表AI大语言模型带来了新一波人工智能浪潮&#xff0c;可以面向科研选题、思维导图、数据清洗、统计分析、高级编程、代码调试、算法学习、论文检索、写作、翻译、润色、文献辅助…

车规级存储芯片SPI NOR Flash

国产SPI NOR Flash厂家聚辰提供多种容量选择&#xff0c;可满足多种实时操作系统所需的不同存储空间&#xff1b;并且&#xff0c;拥有四种不同电压范围&#xff0c;分别为3V、1.8V、1.2V以及针对电池供电应用推出的1.65V~3.6V宽压供电的产品系列&#xff1b;同时&#xff0c;提…

【flask+python】利用魔术方法,更优雅的封装model类

定义model # Time :2024-2024/2/27-14:49 # Email :514422868qq.com # Author :Justin # file :user.py # Software :01-fishbook from app.model.base import Base from sqlalchemy import Column, Integer, SmallInteger, String from werkzeug.security …

深入浅出JVM(十七)之并发垃圾收集器CMS

上篇文章介绍用户线程与GC线程并发执行时可能产生的问题以及使用三色标记法演示原始快照和增量更新两种解决方案 这篇文章将主要介绍并发垃圾收集器中的CMS&#xff0c;其中CMS使用增量更新来解决对象消失问题&#xff0c;如果不了解增量更新的同学可以查看上篇文章深入浅出JV…