嘿,朋友,其实 CSS 动画超简单的 - 时间函数篇(贝塞尔曲线、steps,看完还不懂算我输)

news2024/11/28 17:56:32

分配内存 - new

官方定义:new是一个分配内存的内置函数,第一个参数是类型,而不是值,返回的值是指向该类型新分配的零值的指针

func new(Type) *Type 

我们平常在使用指针的时候是需要分配内存空间的,未分配内存空间的指针直接使用会使程序崩溃,比如这样:

 var a *int64
*a = 10 

我们声明了一个指针变量,直接就去使用它,就会使用程序触发panic,因为现在这个指针变量a在内存中没有块地址属于它,就无法直接使用该指针变量,所以new函数的作用就出现了,通过new来分配一下内存,就没有问题了:

var a *int64 = new(int64)
*a = 10 

上面的例子,我们是针对普通类型int64进行new处理的,如果是复合类型,使用new会是什么样呢?来看一个示例:

func main() { // 数组 array := new([5]int64) fmt.Printf("array: %p %#v \n", &array, array) // array: 0xc0000ae018 &[5]int64{0, 0, 0, 0, 0} (*array)[0] = 1 fmt.Printf("array: %p %#v \n", &array, array) // array: 0xc0000ae018 &[5]int64{1, 0, 0, 0, 0} // 切片 slice := new([]int64) fmt.Printf("slice: %p %#v \n", &slice, slice) // slice: 0xc0000ae028 &[]int64(nil) (*slice)[0] = 1 fmt.Printf("slice: %p %#v \n", &slice, slice) // panic: runtime error: index out of range [0] with length 0 // map map1 := new(map[string]string) fmt.Printf("map1: %p %#v \n", &map1, map1) // map1: 0xc00000e038 &map[string]string(nil) (*map1)["key"] = "value" fmt.Printf("map1: %p %#v \n", &map1, map1) // panic: assignment to entry in nil map // channel channel := new(chan string) fmt.Printf("channel: %p %#v \n", &channel, channel) // channel: 0xc0000ae028 (*chan string)(0xc0000ae030) channel <- "123"// Invalid operation: channel <- "123" (send to non-chan type *chan string)
} 

从运行结果可以看出,我们使用new函数分配内存后,只有数组在初始化后可以直接使用,slice、map、chan初始化后还是不能使用,会触发panic,这是因为slice、map、chan基本数据结构是一个struct,也就是说他里面的成员变量仍未进行初始化,所以他们初始化要使用make来进行,make会初始化他们的内部结构,我们下面一节细说。还是回到struct初始化的问题上,先看一个例子:

type test struct { A *int64
}

func main() { t := new(test) *t.A = 10 // panic: runtime error: invalid memory address or nil pointer dereference // [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x10a89fd] fmt.Println(t.A)
} 

从运行结果得出使用new()函数初始化结构体时,我们只是初始化了struct这个类型的,而它的成员变量是没有初始化的,所以初始化结构体不建议使用new函数,使用键值对进行初始化效果更佳。

其实** new 函数在日常工程代码中是比较少见的,因为它是可以被代替,使用T{}方式更加便捷方便。**

初始化内置结构 - make

在上一节我们说到了,make函数是专门支持 slice、map、channel 三种数据类型的内存创建,其官方定义如下:

func make(t Type, size …IntegerType) Type

大概翻译最上面一段:make内置函数分配并初始化一个slice、map或chan类型的对象。new函数一样,第一个参数是类型,而不是值。与new不同,make的返回类型与其参数的类型相同,而不是指向它的指针。结果的取决于传入的类型。

不同的类型初始化可以使用不同的姿势,主要区别主要是**长度(len)和容量(cap)**的指定,有的类型是没有容量这一说法,因此自然也就无法指定。如果确定长度和容量大小,能很好节省内存空间。

func main(){slice := make([]int64, 3, 5)fmt.Println(slice) // [0 0 0]map1 := make(map[int64]bool, 5)fmt.Println(map1) // map[]channel := make(chan int, 1)fmt.Println(channel) // 0xc000066070
} 

这里有一个需要注意的点,就是slice在进行初始化时,默认会给零值,在开发中要注意这个问题,我就犯过这个错误,导致数据不一致。

new和make区别总结

  • new函数主要是为类型申请一片内存空间,返回执行内存的指针* make函数能够分配并初始化类型所需的内存空间和结构,返回复合类型的本身。* make函数仅支持** channel、map、slice 三种类型**,其他类型不可以使用使用make。* new函数在日常开发中使用是比较少的,可以被替代。* make函数初始化slice会初始化零值,日常开发要注意这个问题。二者都在堆上分配内存,但是它们的行为不同,适用于不同的类型。

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

我的理解,new返回一个变量的指针,但是这个指针指向空,你不可以直接对该指针进行操作,否则会报错,除非你将该指针指向一个该类型变量的地址。 make返回一个该类型的变量,以切片变量为例,上面提到,make适用于创建切片、map和channel,但new也可以创建。

new与make函数初始化

先看个图来直观区分下二者区别

通过下面代码,可以看出来new 和 make创建变量时的差别

package main

import "fmt"

func main() { //使用make创建切片,返回的是变量本身 s1 := make([]int, 5, 10) fmt.Printf("use make create slise type %T value %v \n", s1, s1) //use make create slise type []int value [0 0 0 0 0] s1[0] = 123 s1[4] = 321 fmt.Printf("make s1 type %T value %v \n", s1, s1) //make s1 type []int value [123 0 0 0 321] //# 使用new 创建切片,返回的是切片变量的指针 s2 := new([]int) fmt.Printf("use new create slise type %T value %v \n", s2, s2) //use new create slise type *[]int value &[] fmt.Printf("new s2 type %T value %v \n", *s2, *s2) //new s2 type []int value [] // 想要赋值的话需要使用*解引用 // 这里虽然不报语法错误,但是如果尝试直接使用(*s2)[0] = 123的话会有运行时错误, 【并没有给给结构体内容赋空间】 // panic: runtime error: index out of range s2 = &s1 //需要将变量指针指向一个该类型变量的地址 (*s2)[0] = 123 (*s2)[4] = 3211 fmt.Printf("new s2 type %T value %v \n", s2, s2) //new s2 type *[]int value &[123 0 0 0 3211] //s2的修改也会影响s1 fmt.Printf("s1 type %T value %v \n", s1, s1) //s1 type []int value [123 0 0 0 3211] m1 := make(map[string]string) m1["name"] = "yangyanxing" m1["age"] = "30" fmt.Printf("m1 use make create type:%T value %v \n", m1, m1) //m1 use make create type:map[string]string value map[age:30 name:yangyanxing] m2 := new(map[string]string) fmt.Printf("m2 use new create type:%T value %v \n", m2, m2) //m2 use new create type:*map[string]string value &map[] //直接赋值会报 panic: assignment to entry in nil map m2 = &m1 (*m2)["name"] = "fan" //对m2的修改也会影响到m1 fmt.Printf("after m2 change m1 value is %v", m1) //after m2 change m1 value is map[age:30 name:fan]
} 

map的初始化

map有以下两种初始化方法

  • 使用make函数* 直接使用map初始化
package main

import "fmt"

func main() { //使用make初始化map mp2 := make(map[string]string) mp2["name"] = "yangyanxing" mp2["age"] = "18" fmt.Println("m2 address ", &mp2) // out:m2 address&map[name:yangyanxing age:18] mp3 := map[string]int{} //这里要有{},花括号里如果没有内容则说明初始化了一个空字典 mp3["yang"] = 18 mp3["fan"] = 20 fmt.Println(mp3) //out:map[yang:18 fan:20] mp4 := map[string]int{"yang": 20,"fan":21, //即使是最后一个也要有逗号 } fmt.Println(mp4) //out:map[yang:20 fan:21] mp5 := map[string]int{"yang": 30} //写在同一行则不用加逗号 fmt.Println(mp5) //out: map[yang:30] mp6 := make(map[string]int, 1) //还可以给map加一个容量 mp6["yang"] = 30 fmt.Println("mp6 lens is ", len(mp6), "address:", &mp6) //out:mp6 lens is1 address: &map[yang:30] mp6["fan"] = 31 fmt.Println("mp6 lens is ", len(mp6), "address:", &mp6) //out:mp6 lens is2 address: &map[yang:30 fan:31] //也可以使用new,但是不可以直接对其进行赋值,因为此时它返回的是一个空指针 //需要指向一个该类型的变量地址以后才可以进行操作 mp7 := new(map[string]int) fmt.Println(mp7) //out:&map[] //(*mp7)["yang"] = 100 //会报运行时错误 mp7 = &mp6 //mp7["fan"] = 1000 //也不可以直接使用mp7,需要使用* 先解引用 (*mp7)["yang"] = 100 //这时就不会报运行时错误 fmt.Println(mp7) //out:&map[yang:100 fan:31]
} 

slice切片的初始化

同样可以通过make和切片本身进行初始化

package main

import "fmt"

func main() { //使用make初始化切片,需要传一个len长度,容量cap为可选 //如果不传的话则长度和容量相同 sls1 := make([]int, 5, 10) sls1[0] = 100 //append 追加到尾部,这里有点意思 sls1 = append(sls1, 200) // ... 三个点,go里的语法糖,展开前面的切片 sls1 = append(sls1, []int{30, 40}...) fmt.Println(sls1, len(sls1), cap(sls1)) //out: [100 0 0 0 0 200 30 40] 8 10 sls1 = append(sls1, 3, 4, 6) //超过切片原有容量以后将会发生扩容 fmt.Println(sls1, len(sls1), cap(sls1)) //out: [100 0 0 0 0 200 30 40 3 4 6] 11 20 sls2 := make([]int, 3) sls2[1] = 123 fmt.Println(sls2, len(sls2), cap(sls2)) //out: [0 123 0] 3 3 //直接初始化 sls3 := []int{} sls3 = append(sls3, 10, 20) fmt.Println(sls3, len(sls3), cap(sls3)) //out: [10 20] 2 2 sls4 := []int{1, 2, 3} sls5 := []int{1,2,5, //这里的逗号不能省 } fmt.Println(sls4, sls5) //out: [1 2 3] [1 2 5] //使用new创建切片,和map一样,返回的也是指针,不能直接对其进行操作 //需要先指向一个变量的地址 sls6 := new([]int) fmt.Println(sls6) //out: &[] sls6 = &sls4 fmt.Println(sls6) //out: &[1 2 3]

} 

array数组的初始化

数组不能使用make初始化,但是可以使用new初始化

package main

import "fmt"

type person struct { name string ageint
}

func main() { fmt.Println("数组的初始化") //声明并初始化一个空数组,里面的元素值为类型的零值 arr1 := [2]int{} fmt.Println(arr1) //out: [0 0] //初始化时将元素值写上 arr2 := [2]int{1, 3} fmt.Println(arr2) //out: [1 3] //只写一个,不写的是零值 arr3 := [2]int{1} fmt.Println(arr3) //out: [1 0] //arr4 := make([2]int) //数组不能使用make var arr5 [2]int arr5[0] = 100 fmt.Println(arr5) //[100 0] //不指定数组大小,使用... 三点号让其自动展开计算 arr6 := [...]int{2, 4, 6, 8} fmt.Println(arr6, len(arr6)) //out: [2 4 6 8] 4 //使用new创建一个数组,得到的是一个指针 arr7 := new([3]int) fmt.Println(arr7) //out: &[0 0 0] //可以直接对指针进行操作 arr7[0] = 3 //和使用*解引用作用一样 (*arr7)[1] = 4 fmt.Println(arr7) //out: &[3 4 0]
} 

struct结构体的初始化

package main

import "fmt"

type person struct { name string ageint
}

func main() { fmt.Println("结构体的初始化") //使用new,返回结构体指针 stru1 := new(person) fmt.Println(stru1) //out &{ 0} ,默认是字段的零值 //可以直接使用这个指针来操作变量 //和使用*解引用效果一样 stru1.name = "yangyanxing" (*stru1).age = 18 fmt.Println(stru1, *stru1) //&{yangyanxing 18} {yangyanxing 18} //只指定一个字段,没有指定的默认零值 stru2 := person{name: "fan"} fmt.Println(stru2) //{fan 0} //全部指定,字段的顺序可以不按照定义时的顺序 stru3 := person{age: 18, name: "yang"} fmt.Println(stru3) //{yang 18} //按照结构体顺序初始化,这时元素的值必须都写全了 stru4 := person{"fan", 17} fmt.Println(stru4) //{fan 17}
} 

为什么我们不能对任何事物都使用 make ?

看下面获得结构体的指针方法

s := &SomeStruct{}
v := SomeStruct{}
s := &v// 相同
s := new(SomeStruct) // 也相同 

由于 make 旨在创建这三种内置泛型类型,因此必须由运行时提供,因为无法在 Go 中直接表达 make 的功能签名。

尽管 make 创建了泛型切片,映射和通道值,但它们仍然只是常规值;make 不返回指针值。

如果为有利于 make 而删除 new,您将如何构造指向初始值的指针?

var x1 *int
var x2 = new(int) 

x1 和 x2 具有相同的类型,*int,x2 指向初始化的内存,并且可以安全地取消引用,相同的是对于 x1 都不为 true。

为什么我们不能对任何事物都使用 new ?

尽管 new 很少使用,但其行为已经被很好地指定了。

new(T) 始终返回一个 * T 指向已初始化的 T。由于 Go 没有构造函数,因此该值将被初始化为 T 的 零值。

使用 new 构造指向 slice,map 或 channel 的指针,目前可以使用并且与 new 的行为一致。

s := new([]string)
fmt.Println(len(*s))// 0
fmt.Println(*s == nil) // true

m := new(map[string]int)
fmt.Println(m == nil) // false
fmt.Println(*m == nil) // true

c := new(chan int)
fmt.Println(c == nil) // false
fmt.Println(*c == nil) // true 

Go中使用new创建对象和直接字面量创建对象的区别

使用new创建对象返回对象指针,而直接使用字面量创建对象返回对象本身。

package main

import "fmt"

type person struct { name string ageint
}

func main() { s1 := person{name: "xm",age:11, } s2 := new(person) s2.name = "xh" s2.age = 12 fmt.Printf("%T", s1)// main.stu fmt.Printf("%s", s1.name) // xm fmt.Printf("%T", s2)// *main.stu fmt.Printf("%s", s2.name) // xh

} 

最后

最近找到一个VUE的文档,它将VUE的各个知识点进行了总结,整理成了《Vue 开发必须知道的36个技巧》。内容比较详实,对各个知识点的讲解也十分到位。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

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

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

相关文章

Java自定义注解

目录 一、什么是自定义注解 1&#xff09;Java注解简介 2&#xff09;Java注解分类 JDK基本注解 JDK元注解 自定义注解 如何自定义注解&#xff1f; 二、自定义注解 1&#xff09;获取类上注解值 2&#xff09;获取类属性上的注解属性值 3&#xff09;获取方法上的注…

WireShark 常用协议分析

WireShark 常用协议分析 1.3 实战&#xff1a;使用 WireShark 对常用协议抓包并分析原理 协议分析的时候 我们 关闭混淆模式&#xff0c; 避免一些干扰的数据包存在。 1.3.1 常用协议分析 - ARP 协议 地址解析协议 &#xff08;英语&#xff1a;Address Resolution Protocol&…

从内核角度看网络包发送流程

一、前置知识 1、RingBuffer结构详解 关于RingBuffer网上有很多说法&#xff0c;有的人说RingBuffer是系统启动时就预先申请好的一个环形数组&#xff0c;有的人说RingBuffer是在接收或发送数据时才动态申请的一个环形数组&#xff0c;那么到底RingBuffer的结构是怎么样的呢&…

《吉师作业》(2)之迟来的答案

前言 &#x1f340;作者简介&#xff1a;吉师散养学生&#xff0c;为挣钱努力拼搏的一名小学生。 &#x1f341;个人主页&#xff1a;吉师职业混子的博客_CSDN博客-python学习,HTML学习,清览题库--C语言程序设计第五版编程题解析领域博主 &#x1fad2;文章目的&#xff1a;我不…

初识C++(二)

简述 &#xff1a;本篇就缺省参数 和 函数重载 方面进行初步学习 &#xff0c;对比C语言学习C这两个语法&#xff0c;从而感受C在此方面对C语言进行的补充。 目录 缺省参数 什么是缺省参数 缺省参数的分类 缺省参数的应用 函数重载 什么是函数重载 函数重载的三种情况 支…

【JavaSE】函数or方法?方法的重载讲解

文章目录什么是方法如何定义方法方法的调用过程形参与实参的关系方法的重载为什么要重载重载的概念方法签名递归什么是方法 在C语言的学习中我们学习到了一个概念叫做函数&#xff0c;那么在Java的语法中有没有类似函数的东西的&#xff0c;答案是有的&#xff0c;但是在Java的…

strimzi实战之一:简介和准备

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码)&#xff1a;https://github.com/zq2599/blog_demos 关于strimzi strimzi是一个开源项目&#xff0c;已加入了CNCF&#xff0c;官网地址&#xff1a;https://strimzi.io/借助strimzi&#xff0c;既能快速部署ka…

【生日快乐】搜索技术【深度优先搜索】 - 回溯法

搜索技术【深度优先搜索】 - 回溯法 回溯法是一种选优搜索法&#xff0c;按照选优条件深度优先搜索&#xff0c;以达到目标。当搜索到某一步时&#xff0c;发现原先的选择并不是最优或达不到目标&#xff0c;就退回一步重新选择&#xff0c;这种走不通就退回再走的技术被称为回…

如何用 Elasticsearch 实现 Word、PDF,TXT 文件的全文内容检索?

简单介绍一下需求 能支持文件的上传&#xff0c;下载 要能根据关键字&#xff0c;搜索出文件&#xff0c;要求要能搜索到文件里的文字&#xff0c;文件类型要支持 word&#xff0c;pdf&#xff0c;txt 文件上传&#xff0c;下载比较简单&#xff0c;要能检索到文件里的文字&am…

2022-ISCTF-部分MISC和PWN

misc 两层编码 第一层 sha256掩码爆破 第二层 base64解码找到key import string,sys from hashlib import sha256 from multiprocessing import Process from Crypto.Util.number import * from pwn import * import base64 from primefac import * context(log_leveldebug)…

【STL】容器 - set和map的使用

目录 前言 一.键值对 1.在SGI - STL中对键值对的定义: 2.make_pair 二.set 1.set的概念与注意事项 2.set的使用(常用接口) <1>.构造函数 <2>.迭代器与范围for <3>.插入和查找 <4>.删除erase <5>.计数count 三.map 1.map的概念与注…

洛谷千题详解 | P1012 [NOIP1998 提高组] 拼数【C++、Java语言】

博主主页&#xff1a;Yu仙笙 专栏地址&#xff1a;洛谷千题详解 目录 题目描述 输入格式 输出格式 输入输出样例 解析&#xff1a; C源码&#xff1a; C源码2&#xff1a; C源码3&#xff1a; Java源码&#xff1a; ---------------------------------------------------------…

element-ui upload图片上传组件使用

图片上传前端收集 数据 再调用接口发送到后端 组件标签内的参数&#xff1a; 参数说明类型可选值默认值action必选参数&#xff0c;上传的地址string——headers设置上传的请求头部object——multiple是否支持多选文件boolean——data上传时附带的额外参数object——name上传…

【数据结构】链表OJ第一篇 —— 移除链表元素 反转链表 合并两个有序链表

文章目录0. 前言1. 移除链表元素2. 反转链表3. 合并两个有序链表4. 结语0. 前言 上篇博客中&#xff0c;我们学习了实现了单链表。但是仅仅实现并不算掌握&#xff0c;所以我们需要做些题目来练习巩固。而从今天开始的几期&#xff0c;anduin 都会为大家带来链表OJ题&#xff…

在Linux环境下VScode中配置ROS、PCL和OpenCV开发环境记录

一.安装必要的插件 打开VScode&#xff0c;在开展中安装CMake、CMake Tools&#xff0c;ROS和catkin-tools插件&#xff0c;截图如下&#xff0c;安装后重新打开VScode插件生效。 二.创建ROS工作空间 在选择的路径下&#xff0c;打开终端创建工作空间&#xff0c;具体命令如下…

【概率论笔记】正态分布专题

文章目录一维正态分布多维正态分布n维正态分布二维正态分布一维正态分布 设X~N(μ,σ2)X\text{\large\textasciitilde}N(\mu,\sigma^2)X~N(μ,σ2)&#xff0c;则XXX的概率密度为f(x)12πσe−(x−μ)22σ2f(x)\frac{1}{\sqrt{2\pi}\sigma}e^{-\frac{(x-\mu)^2}{2\sigma^2}}f(…

WXML模板语法

文章目录1、数据绑定1.1 数据绑定的基本原则1.2在data中定义页面的数据1.3 Mustache语法的格式1.4 Mustache语法的应用场景1.5 算数运算2、事件绑定2.1 小程序常用的事件2.2事件对象的属性列表2.3 target和currentTarget的区别2.4 <font colorred>bindtap的语法格式2.5 在…

狗厂员工来面试本想难为一下,结果被虐得连console.log也不敢写了

这次说到的面试题是关于node服务端内存溢出的问题&#xff0c;狗厂员工来面试本想难为一下&#xff0c;现在我连console.log也不敢写了 关于这道node内存溢出的问题&#xff0c;大哥从以下几个方面讲的&#xff0c;讲完我觉得自己得到了升华&#xff0c;现在搞得连代码也快不敢…

2.24 OrCAD Cadence16.6怎么更改原理图中做好的库文件?

笔者电子信息专业硕士毕业&#xff0c;获得过多次电子设计大赛、大学生智能车、数学建模国奖&#xff0c;现就职于南京某半导体芯片公司&#xff0c;从事硬件研发&#xff0c;电路设计研究。对于学电子的小伙伴&#xff0c;深知入门的不易&#xff0c;特开次博客交流分享经验&a…

FPGA代码设计规范一些探讨

代码设计规范的重要性 经过一段的工作积累已经慢慢进入了提高和进阶的阶段&#xff0c;在这篇博客里多聊一聊在现实工作中的话题&#xff0c;比如代码规范以及如何尽快接手前人代码&#xff0c;快速定位项目问题。 显然每个FPGA工程师的设计理念和代码风格很多情况下有一些差别…