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

news2024/11/17 4:42:37

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=3
		d = c[:2]             //两个元素,len=2,cap=3
		e = c[:2:cap(c)]      //两个元素,len=2,cap=3
		f = c[:0]             //没有元素,len=0,cap=3
		g = make([]int, 3)    //三个元素,len=3,cap=3
		h = 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 *Stduent
	var peo People = stu

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

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

  • 再来看看非空接口

Go中的定义为:

type iface struct {
  tab  *itab
  data unsafe.Pointer
}

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

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

type S struct {
}

func f(x interface{}) {
}

func g(x *interface{}) {
}

func main() {
	s := S{}
	p := &s
	f(s) //A
	g(s) //B 运行出错
	f(p) //C
	g(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.coloradmin.cn/o/1540952.html

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

相关文章

C++例子

#include<iostream> using namespace std;//抽象类 //抽象cpu类 class CPU { public:virtual void calcuate()0; }; //抽象显卡类 class VideoCard { public:virtual void display()0; }; //抽象内存条类 class Memory { public:virtual void storage()0;};//电脑类 clas…

vue3+ts+vite axios封装请求并扩展入参

requset.ts import axios, { AxiosResponse } from axios import { getToken, removeToken } from /utils/auth// 创建axios实例 const service axios.create({baseURL: , // 所有的请求地址前缀部分(没有后端请求不用写)timeout: 60000 // 请求超时时间(毫秒)// withCredent…

LeetCode---389周赛

题目列表 3083. 字符串及其反转中是否存在同一子字符串 3084. 统计以给定字符开头和结尾的子字符串总数 3085. 成为 K 特殊字符串需要删除的最少字符数 3086. 拾起 K 个 1 需要的最少行动次数 一、字符串及其反转中是否存在同一子字符串 直接暴力枚举即可&#xff0c;代码…

Linux(Centos)安装mysql 8 并且使用systemctl管理服务

1.下载mysql包 地址 MySQL :: Download MySQL Community Server (Archived Versions) 注&#xff1a;下载我圈住的减压之后里面会有tar.gz 再次减压才会是软件主体 2.安装和准备 yum -y install numactl 安装numactl tar -xvf mysql-8.0.30-el7-x86_64.tar 拆分 …

算法思想总结:位运算

创作不易&#xff0c;感谢三连支持&#xff01;&#xff01; 一、常见的位运算总结 标题 二、位1的个数 . - 力扣&#xff08;LeetCode&#xff09; 利用第七条特性&#xff1a;n&&#xff08;n-1&#xff09;干掉最后一个1&#xff0c;然后每次都用count去统计&#xff…

目标检测——PP-YOLOv2算法解读

PP-YOLO系列&#xff0c;均是基于百度自研PaddlePaddle深度学习框架发布的算法&#xff0c;2020年基于YOLOv3改进发布PP-YOLO&#xff0c;2021年发布PP-YOLOv2和移动端检测算法PP-PicoDet&#xff0c;2022年发布PP-YOLOE和PP-YOLOE-R。由于均是一个系列&#xff0c;所以放一起解…

【算法与数据结构】 C语言实现单链表队列详解

文章目录 &#x1f4dd;队列&#x1f320; 数据结构设计&#x1f309;初始化队列函数 &#x1f320;销毁队列函数&#x1f309;入队函数 &#x1f320;出队函数&#x1f309;获取队首元素函数 &#x1f320;获取队尾元素函数&#x1f309; 判断队列是否为空函数&#x1f309;获…

学习ReentrantLock 原理

ReentrantLock 与 synchronized 锁的实现&#xff1a;synchronized 是 JVM 实现的&#xff0c;而 ReentrantLock 是 JDK 实现性能&#xff1a;新版本 Java 对 synchronized 进行了很多优化&#xff0c;synchronized 与 ReentrantLock 大致相同使用&#xff1a;ReentrantLock 需…

tauri应用实现一键快速更新版本

tauri应用实现一键快速更新版本 创建一个项目 pnpm create tauri-app根据配置选择就可以 pnpm tauri dev启动项目 ##更新配置 打包配置在src-tauri/tauri.conf.json 修改打包命令 "bundle": {"active": true,"targets": "all",&qu…

石子合并与果子合并:区间动态规划和贪心

果子合并是如何将一堆果子合并起来所消耗体力最少&#xff0c;石子合并也是将一堆石子合并起来质量最小&#xff0c;但不同的是 石子合并只能相邻的两个合并 。本篇通过讲解这两个相似例题&#xff0c;来学习区间dp与贪心。 目录 石子合并&#xff1a; 题目&#xff1a; 思路…

Dr4g0n

信息收集 # nmap -sn 192.168.56.0/24 -oN live.nmap Starting Nmap 7.94 ( https://nmap.org ) at 2024-03-04 08:52 CST Nmap scan report for 192.168.56.2 Host is up (0.00012s latency). MAC Address: 00:50:56:FE:B1:6F (VMware) Nmap scan report …

【Redis】Redisson实现分布式锁

Redisson是一个在Redis的基础上实现的Java驻内存数据网格&#xff08;In-Memory Data Grid&#xff09;。它不仅提供了一系列的分布式的Java常用对象&#xff0c;还提供了许多分布式服务&#xff0c;其中就包含了各种分布式锁的实现。 官网地址 GitHub地址 Redisson入门 1.引…

docker安装ES7.1.1(单机版)+ik分词器+es-head可视化

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff0c;这篇文章男女通用&#xff0c;看懂了就去分享给你的码吧。 Elasticsearch 是一…

海外媒体发稿:7款爆款标题生成器解析-华媒舍

科普文章是将科学知识普及给大众的一种方式&#xff0c;而一个引人入胜的标题往往是吸引读者的第一步。在科普领域中&#xff0c;标题的吸引力至关重要。以下将介绍7款风靡科普界的爆款标题生成器&#xff0c;帮助你创作出引人入胜的科普文章。 1. 情感引爆 情感是人类行为中的…

卷积篇 | YOLOv8改进之主干网络中引入可变形卷积DConv

前言:Hello大家好,我是小哥谈。可变形卷积模块是一种改进的卷积操作,它可以更好地适应物体的形状和尺寸,提高模型的鲁棒性。可变形卷积模块的实现方式是在标准卷积操作中增加一个偏移量offset,使卷积核能够在训练过程中扩展到更大的范围,从而实现对尺度、长宽比和旋转等各…

QML 布局管理器之GridLayout 项目demo

一.气体控制效果图 二.界面布局代码实现 //DottedLline.qml 虚线绘制 import QtQuick 2.12 import QtQuick.Shapes 1.12Shape {id:canvaswidth: parent.widthheight: parent.heightShapePath{strokeStyle: ShapePath.DashLinestartX: 8startY: 10dashPattern: [1, 3]PathLine{…

多线程和线程同步

文章目录 进程和线程线程的操作线程创建线程退出线程回收线程分离线程取消和ID比较 线程同步互斥锁死锁读写锁条件变量信号量 进程和线程 线程是轻量级的进程&#xff0c;在Linux环境下线程的本质还是进程。 在计算机上运行的程序是一组指令及指令参数的组合&#xff0c;指令按…

Web前端-JS

JavaScript&#xff0c;简称js&#xff1a;负责网页的行为&#xff08;交互效果&#xff09;。是一门跨平台&#xff0c;面向对象的脚本语言&#xff08;编写出来的语言不需要编译&#xff0c;通过浏览器的解释就可以运行&#xff09; JS引入方式 1.内嵌样式 这样打开页面就会…

毕业答辩PPT模板涵盖多种风格,包括母版的设计及主题色的设计

毕业答辩PPT模板涵盖多种风格&#xff0c;包括母版的设计及主题色的设计 前言一两个页面的展示研究内容主题概述主题内容一&#xff1a;主要面向三点研究内容主题内容二&#xff1a;主要面向两点研究内容主题内容三&#xff1a;主要面向包含应用开发的研究 前言 之前做了有关开…

Oracle Data Guard部署

Oracle的主备DG搭建 1. 修改主机名,同步时间 主库IP&#xff1a;192.168.100.137 备库IP&#xff1a;192.168.100.138配置主机名(主库) Hostname zygjpdb vim /etc/hosts 192.168.100.137 zygjpdb 192.168.100.138 zygjsdbvim /etc/sysconfig/network HOSTNAMEzygjpdb ------…