Go --- 编程知识点及其注意事项

new与make

二者都是用于内存分配,当声明的变量是引用类型时,不能给该变量赋值,因为没有分配空间。

我们可以用new和make对其进行内存分配。

  • 首先说说new

new函数定义

func new(Type) *Type

传入一个类型,返回一个指向分配好该类型的地址的指针,并将变量赋零值。

在敲代码时并不常用。

  • 再来说说make

make也是用于内存分配的,但是和new不同。

make有明确的分工,它只能用于slice、map、channel。因为三者都是引用类型,所以并不需要返回指针,而且不会置零值。

make与new都是分配堆空间。

数据定义

1、当给返回值命名时,如果已经默认了返回值名称,则所有返回值都要有默认名。如

myFunc(x,y int)(sum int,error)

是不被允许的,编译会报错,如果一个返回值有名称则也需要用()括起来。

2、结构体比较

一般来说结构体是可以使用“==”比较的,只有当结构体定义时属性顺序不同,或者结构体中有不可比较的类型,如map和slice。

带有map和slice的结构体可以使用reflect库下的

DeepEqual(x, y any) bool

进行比较。

不同结构体实例化出来的对象比较结果必然也会不同。

3、string与nil类型

nil 可以用作 interface、function、pointer、map、slice 和 channel 的“空值”,但是不能作为string类型的空值。

所以nil不能作为string类型的返回值。

4、常量

变量在程序运行中分配内存,而常量在编译器预处理阶段就开始分配。

内存四区:
  • 栈区

空间较小,要求数据读写性能高,数据存放时间较短暂。由编译器自动分配和释放,存放函数的参数值、函数的调用流程方法地址、局部变量等(局部变量如果产生逃逸现象,可能会挂在在堆区)

  • 堆区

空间充裕,数据存放时间较久。一般由开发者分配及释放(但是Golang中会根据变量的逃逸现象来选择是否分配到栈上或堆上),启动Golang的GC由GC清除机制自动回收。

  • 全局区

    • 全局变量的开辟是在程序在main之前就已经放在内存中。而且对外完全可见。即作用域在全部代码中,任何同包代码均可随时使用,在变量会搞混淆,而且在局部函数中如果同名称变量使用:=赋值会出现编译错误。
    • 全局变量最终在进程退出时,由操作系统回收。我们在开发的时候,尽量减少使用全局变量的设计
    • 常量区也归属于全局区,常量为存放数值字面值单位,即不可修改。或者说的有的常量是直接挂钩字面值的。
  • 代码区

存放要运行的代码片段。

程序运行前的准备工作:

1、操作系统把物理硬盘代码load到内存

2、操作系统把c代码分成四个区

3、操作系统找到main函数入口执行

在golang中,常量是无法取出地址的,因为字面量符号并没有地址而言。

数组与切片

  • 切片的底层也是数组
  • 切片是可动态扩增长度的数组
  • 初始化方式不同,数组声明时需要先确定容量len=cap,并且会使用0值填充,切片初始化时使用一般使用make,len和cap可以自定义不同的值。

定义切片的几种方式:

	var (a []int               // nil切片b = []int{}           // 空切片c = []int{1, 2, 3}    //三个元素,len=3,cap=3d = c[:2]             //两个元素,len=2,cap=3e = c[:2:cap(c)]      //两个元素,len=2,cap=3f = c[:0]             //没有元素,len=0,cap=3g = make([]int, 3)    //三个元素,len=3,cap=3h = make([]int, 2, 3) //两个元素,len=2,cap=3)

拼接

两个slice在append的时候,记住需要进行将第二个slice进行...打散再拼接。

使用new定义的slice返回的是切片指针,不能直接进行append,需要使用解引用后使用,不如用make。

map

1、赋值问题

Go map如果value是结构体,那么赋值的时候不允许使用map直接给结构体赋值。

原因:说法多种多样,可以分为以下几个点:

1)map作为一个封装好的数据结构,由于它底层可能会由于数据扩张而进行迁移,所以拒绝直接寻址,避免产生野指针;

2)map中的key在不存在的时候,赋值语句其实会进行新的k-v值的插入,所以拒绝直接寻址结构体内的字段,以防结构体不存在的时候可能造成的错误;

3)这可能和map的并发不安全性相关

  • x = y 这种赋值的方式,你必须知道 x的地址,然后才能把值 y 赋给 x。
  • 但 go 中的 map 的 value 本身是不可寻址的,因为 map 的扩容的时候,可能要做 key/val pair迁移
  • value 本身地址是会改变的
  • 不支持寻址的话又怎么能赋值呢

解决办法:

  • 二次赋值
  • 使用结构体指针

2、遍历赋值问题

如果map的value是指针类型,那么不要使用foreach,因为foreach中指针会始终指在最后一个元素的位置。

原因:

go foreach 中的指针变量在每次迭代中都会被重复使用。如果迭代变量在“for”语句之外声明,则执行后它们的值将是最后一次迭代的值.

解决办法:

使用for而不是foreach。

interface

1、赋值问题

比如说:

type People interface {Speak(string) string
}type Stduent struct{}func (stu *Stduent) Speak(think string) (talk string) {if think == "love" {talk = "You are a good boy"} else {talk = "hi"}return
}

那么能不能这么赋值呢?

var peo People = Stduent{}

答案是不行

Stduent does not implement People

可以这么理解,实现接口的是结构体的引用不是结构体本身。

接口分为两种:空接口和非空接口。

  • 先来看空接口

就是没有定义任何方法的接口。

如:

type EmptyInterface interface {   
}

空接口结构体在Go语言中的定义为

type eface struct {      //空接口_type *_type         //类型信息data  unsafe.Pointer //指向数据的指针(go语言中特殊的指针类型unsafe.Pointer类似于c语言中的void*)
}

根据这个定义来看看这个问题:

	var stu *Stduentvar peo People = stu

想一想这个peo会不会是nil?

答案是不是,因为eface定义中data是nil但是_type不是nil,所以peo不是nil。

  • 再来看看非空接口

Go中的定义为:

type iface struct {tab  *itabdata unsafe.Pointer
}

itab里面包含了interface的一些关键信息,比如method的具体实现。

2、inteface{}与*interface{}的区别

type S struct {
}func f(x interface{}) {
}func g(x *interface{}) {
}func main() {s := S{}p := &sf(s) //Ag(s) //B 运行出错f(p) //Cg(p) //D 运行出错
}

Go语言是强类型语言,interface{}作为参数可以传入指针和结构体,*interface{}作为参数只能传入 *interface{}。

channel

特性

go 1.21.6 windows/amd64

  • 给一个nil channel发送数据,会造成死锁
  • 从一个nil channel取出数据,也会造成死锁
  • 往一个已经close的channel发送数据,会报panic
  • 但是从一个已经close的channel取出,不会报panic,如果缓冲区中为空,则返回一个零值
  • 无缓冲的channel是同步的,而有缓冲的channel是非同步的

口诀是:“空读写死锁,写关闭异常,读关闭空零”。
注意使用goroutine时也要注意死锁问题啊

WaitGroup

WaitGroup与goroutine的竞速问题:

问题描述:

const N = 10
var wg = &sync.WaitGroup{}
func main() {for i:= 0; i< N; i++ {go func(i int) {wg.Add(1)println(i)defer wg.Done()}(i)}wg.Wait()
}

结果不唯一,代码存在风险, 所有go未必都能执行到。

就是还没等到Add函数执行,goroutine已经完成了。

解决办法就是将Add函数放在goroutine外,wg.Done在goroutine 内。

大部分内容来自:语雀-刘丹冰Aceld-Go修养之路

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

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

相关文章

从原理到实践:深入探索Linux安全机制(一)

前言 本文将从用户和权限管理、文件系统权限、SELinux、防火墙、加密和安全传输、漏洞管理和更新等几个Linux安全机制中的重要方面&#xff0c;深入探索其工作原理和使用方法。在当今数字化时代&#xff0c;网络安全问题备受关注&#xff0c;Linux作为广泛应用的操作系统之一&…

每日一题 --- 977. 有序数组的平方[力扣][Go]

今天这一题和昨天的知识点是一样的&#xff0c;就是双指针法。 题目&#xff1a; 给你一个按 非递减顺序 排序的整数数组 nums&#xff0c;返回 每个数字的平方 组成的新数组&#xff0c;要求也按 非递减顺序 排序。 示例 1&#xff1a; 输入&#xff1a;nums [-4,-1,0,3,1…

对话悠易科技蔡芳:品牌逐渐回归核心能力建设,布局和构建自己的流量阵地

关于SaaS模式在中国的发展&#xff0c;网上出现多种声音。Marteker近期采访了一些行业专家&#xff0c;围绕SaaS模式以及Martech在中国的发展提出独特观点。悠易科技副总裁蔡芳认为&#xff0c;中国目前存在SaaS的应用场景与客户需求&#xff0c;用户的应用能力也在提升&#x…

containerd源代码分析: 整体架构

本文从代码的大的整体组织上来熟悉containerd项目 containerd项目总的说是一个cs模式的原生控制台程序组。containerd作为服务端来接收处理client的各种请求&#xff0c;如常用的拉取推送镜像&#xff0c;创建查询停止容器&#xff0c;生成快照&#xff0c;发送消息等。client/…

XS2105S,IEEE 802.3af 兼容、用电设备接口控制器集成功率 MOSFET V0.5

XS2105S 为用电设备(PD)提供符合以太网供电(PoE)系统 IEEE802.3af 标准的完整接口。XS2105S 为 PD 提供检测信号、分级信号以及带有浪涌电流控制的 集成隔离功率开关。发生浪涌期间&#xff0c;XS2105S 将电流限 制在 180mA 以内&#xff0c;直到隔离功率 MOSFET 完全开启后切 …

【Linux命令】查看内存占用情况(mem, swap)

1. 方法1&#xff08;top&#xff09; # top2.方法2&#xff08;free&#xff09; # free -h3. 方法3&#xff08;swapon&#xff09; # swapon -s

GraalVM详细安装及打包springboot、java、javafx使用教程(打包springboot3篇)

前言 在当前多元化开发环境下&#xff0c;Java作为一种广泛应用的编程语言&#xff0c;其应用部署效率与灵活性的重要性日益凸显。Spring Boot框架以其简洁的配置和强大的功能深受开发者喜爱&#xff0c;而JavaFX则为开发者提供了构建丰富桌面客户端应用的能力。然而&#xff…

什么是虚拟继承

由于C支持多继承&#xff0c;除了public、protected和private三种继承方式外&#xff0c;还支持虚拟&#xff08;virtual&#xff09;继承&#xff0c;举个例子&#xff1a; #include <iostream> using namespace std;class A {}; class B : virtual public A {}; class…

Vue模块化开发步骤—遇到的问题—解决办法

目录 1.npm install webpack -g 2.npm install -g vue/cli-init 3.初始化vue项目 4.启动vue项目 Vscode初建Vue时几个需要注意的问题-CSDN博客 1.npm install webpack -g 全局安装webpack 直接命令提示符运行改指令会报错&#xff0c;operation not permitted 注意&#…

第一部分:岗位认知

一、谈谈你对大学教师岗位的认识。&#xff08;了解&#xff09; 我想用三种身份来概括我对大学老师的认识&#xff1a;知识的传授者、生命的塑造者、学问的探求者。 &#xff08;一&#xff09;知识的传授者 韩愈曾说&#xff1a;“师者&#xff0c;所以传道授业解惑也。”教师…

算法设计与分析-分支限界——沐雨先生

&#xff08;1&#xff09;抓奶牛问题描述&#xff1a; 农夫约翰被告知逃跑的奶牛的位置&#xff0c;并且要求立即去抓住它。约翰开始的位置在数轴上位置 N &#xff08; 0 ≤ N ≤ 100) &#xff0c;而奶牛的位置在同样一个数轴上的 K (0 ≤ K ≤ 100) 。约翰有两种移动方式&…

Windows下同时安装多个版本的JDK并配置环境变量

说明&#xff1a;这里安装的JDK版本为1.8和17 JDK下载 官方地址: https://www.oracle.com/java/ 我这里下载的是exe安装包 安装这里就不阐述了&#xff0c;安装方法都是一样的。 系统环境变量配置 1、首先新建JDK1.8和17的JAVA_HOME&#xff0c;他们的变量名区分开&#xff…

Disruptor概览

版本&#xff1a;3.4.2 使用案例 初始化 Disruptor<T> disruptor new Disruptor<>(T::new, RING_BUFFER_SIZE,(Runnable r) -> new Thread(r, "MY-DISRUPTOR-THREAD"),ProducerType.MULTI,new SleepingWaitStrategy(50, TimeUnit.MICROSECONDS.to…

只看到真人版《武庚纪》的顶级特效?那你亏大了!

“一不留神就看6集”&#xff0c;一看一个不吱声&#xff0c;相信看过《烈焰》&#xff08;原名&#xff1a;武庚纪&#xff09;的观众或多或少都有和笔者一样的感受。 与其他国产剧不同的是&#xff0c;《烈焰》改编自动画《武庚纪》&#xff0c;“漫改”让他的人物装造更贴近…

基于python+vue超市在线销售系统的设计与实现flask-django-php-nodejs

根据此问题&#xff0c;研发一套超市在线销售系统&#xff0c;既能够大大提高信息的检索、变更与维护的工作效率&#xff0c;也能够方便信息系统的管理运用&#xff0c;从而减少信息管理成本&#xff0c;提高效率。 该超市在线销售系统采用B/S架构、并采用python语言以及django…

【Python 滑块不同的操作】对滑块进行处理,列如切割、还原、去除、无脑识别距离等等

文章日期&#xff1a;2024.03.23 使用工具&#xff1a;Python 类型&#xff1a;图片滑块验证的处理&#xff08;不限于识别距离&#xff09; 使用场景&#xff1a;&#xff1f; 文章全程已做去敏处理&#xff01;&#xff01;&#xff01; 【需要做的可联系我】 AES解密处理&a…

Python计算机二级选择易错题(三)

选择题第02&#xff0c;03&#xff0c;04套 题目来源&#xff1a;python计算机二级真题&#xff08;选择题&#xff09; - 知乎 选择题第02套 选择题第03套 选择题第04套 time()获取当前时间&#xff0c;即计算机内部时间&#xff0c;浮点数&#xff1b;import time库&#x…

用户多部门切换部门,MySQL根据多个部门id递归获取所有上级(祖级)、获取部门的全路径(全结构名称)

背景 之前做过的项目&#xff0c;都是一个用户就一个部门的&#xff0c;现在碰到个一个用户在多个部门的需求&#xff0c;而且需要可以切换不同部门查看不同数据。 就比如说一个大公司下面有多个子公司&#xff0c;每个子公司有好多部门、子部门等等&#xff0c;然后有部分用…

【赠书第21期】游戏力:竞技游戏设计实战教程

文章目录 前言 1 竞技游戏设计的核心要素 1.1 游戏机制 1.2 角色与技能 1.3 地图与环境 2 竞技游戏设计的策略与方法 2.1 以玩家为中心 2.2 不断迭代与优化 2.3 营造竞技氛围与社区文化 3 实战案例分析 4 结语 5 推荐图书 6 粉丝福利 前言 在数字化时代的浪潮中&…

Rust之构建命令行程序(五):环境变量

开发环境 Windows 11Rust 1.77.0 VS Code 1.87.2 项目工程 这次创建了新的工程minigrep. 使用环境变量 我们将通过添加一个额外的功能来改进minigrep:一个不区分大小写的搜索选项&#xff0c;用户可以通过环境变量打开该选项。我们可以将此功能设置为命令行选项&#xff0c;…