当前位置: 首页 > 编程笔记 >

golang新手不注意可能会出现的一些小问题

杨安歌
2023-03-14
本文向大家介绍golang新手不注意可能会出现的一些小问题,包括了golang新手不注意可能会出现的一些小问题的使用技巧和注意事项,需要的朋友参考一下

go简介

语言哲学

C语言是纯过程式的,这和它产生的历史背景有关。Java语言则是激进的面向对象主义推崇者,典型表现是它不能容忍体系里存在孤立的函数。而Go语言没有去否认任何一方,而是用批判吸收的眼光,将所有编程思想做了一次梳理,融合众家之长,但时刻警惕特性复杂化,极力维持语言特性的简洁,力求小而精

Go语言反对函数和操作符重载(overload),而C++、Java和C#都允许出现同名函数或操作符,只要它们的参数列表不同。

其次,Go语言支持类、类成员方法、类的组合,但反对继承,反对虚函数(virtual function)和虚函数重载。确切地说,Go也提供了继承,只不过是采用了组合的文法来提供

最近在整理之前写程序,学习时所记录的有道云笔记,发现一些有意思的小点跟大家分享一下。如有错误请大家给指出

一、闭包 defer

闭包(匿名函数)

func test(){
 i, n := 1 ,2;
 defer func(a int){
  fmt.Println("defer:", a , n); //n被闭包引用
 }(i) //复制i的值
 i , n = i+1,n+2;
 fmt.Println(i , n);
}

我们看一下结果:

2 4
defer: 1 4

为什么会这样?是因为闭包复制的是原对象指针,出现了延迟引用现象。我们在使用闭包的时候要注意这个问题,同样在for 循环中 也会出现类似现象。

二、Map

前一段时间在论坛看到一个问题

type Data struct{
 AABB [2]float64
}
var m map[string]Data = make(map[string]Data,1)
m["xxx"] = Data{}
m["xxx"].AABB[0]=1.0
m["xxx"].AABB[1]=2.0<br data-filtered="filtered">#以上代码go build 通不过,错误提示cannot assign to m["xxx"].AABB[0]

这是一个网友给出的答案

type Data struct{
 AABB [2]float64
} 
m := make(map[string]*Data,1)
m["xxxx"] = Data{}
m["xxxx"].AABB[0] = 1.0
m["xxxx"].AABB[1] = 2.0
#这样写就对了,你的 m["xxxx"] 返回的是值,不是一个可取地址的变量

这个网友的答案可以编译成功,但是不可取,他犯了很多新手都容易出现的问题

why?Golang中的map元素属性被设计为只读的,并不期望被修改,并且从 map 中取回的是一个value也是临时复制品。并且map是一个hash 结构,当hash扩容时,键值的存储位置就会发生改变。如果这个时候我们对 m["xxxx"].AABB[0] = 1.0 修改,不知道指针会发什么。大家有兴趣可以看看Go Hashmap内存布局和实现

如果我们想修改最好这样

type Data struct{
 AABB [2]float64
}
m := make(map[string]*Data,1)
m["xxxx"] = &Data{}
d := m["xxxx"]
d.AABB[0] = 1.0
d.AABB[1] = 2.0
m["xxxx"] = d

三、nil

先看一段代码,当然这种场景不常见,但是能让我们更好的理解nil

func t(){
 var i *int = nil;
 var n interface{} = i;
 fmt.Println(n==nil); //false
}

可能很多小伙伴都会有疑问都是nil 为啥会不相等。我们先分别看一下pointer,interface的结构体和当pointer,interface为nil时的结构

uintptr
type interfaceStruct struct {
  v *_value // 实际值
  t *_type // 实际值的类型信息
}
uintptr(0) == nil
type interfaceStruct struct {
  v:uintptr(0)
  t:uintptr(0)
} == nil

由此我们可以看出nil其实就是指针 interface的零值

这时候我们在来解释为啥为flase就很容易了

func t(){
 var i *int = nil; // (*int)nil
 var n interface{} = i; // interace{}((*int)nil)
 fmt.Println(n==nil); // type interfaceStruct struct {
                 //  v: uintptr(0),
                 //  t: (*int)
                 // }
}

官方文档规定可以为nil的类型还有 slice ,map ,channel ,function 。

可能有些朋友可能会问为啥没有error类型,那是因为error 只是程序预设的接口方法, err nil 也会出现类似的问题,官方有一个文档也给出了解释,传送门

type error interface { 
 Error() string 
}  

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对小牛知识库的支持。

 类似资料:
  • 如果我们转而使用软件包,需要注意的主要考虑因素和危险是什么?什么可能会坏?是否会影响调试、测试、构建(使用FinalBuilder)或维护的便利性?运行时内存利用率是否会增加到不可接受的程度,因为我们将在运行时加载整个BPL,而不仅仅是链接器所需的单元? 我知道,唯一真正的答案将来自于在我们的具体应用程序中尝试它,但我将非常感谢任何已经走上这条道路或拒绝它的人的一些建议。

  • 我有一个JFrame,它在JScrollPane中包含一个JSplitPane(因此,如果窗口很大,用户可以滚动)。JSplitPane包含作为顶部组件的JTabbedPane,以及作为底部组件的graphics。现在我想读一个。csv并在我的jtabbedpane中显示它。我可以使用第二个JScrollPane在列表中滚动。问题来了,当我在我的程序中导入。csv时,第一个JScrollPane似

  • 我对Hibernate和JPA存储库的实现有问题。 我得到了关于错误: "发生异常后不要刷新会话" 这是从第节开始的- 消息表: 用户表: 服务: 可能这就是问题所在——这是一个例外。会议仍然开放。当然,我在服务中有事务注释。 以及执行日志:

  • 其他还有很多功能,由于个人觉得不是那么的重要,所以此处暂称其为小功能。 虽然此处称为小功能,但是真正等你需要用到的时候,也会发现,真的很贴心,很好用。 3.19.1. 支持双击Tab标签关闭文件 想要快速关闭某个文件,可以通过双击该文件的Tab: 注意 不过需要注意的是,默认是关闭了此功能的,需要的话,去开启此功能: 设置(T) ⇒ 首选项... ⇒ 常用 ⇒ 标签栏 ⇒ 勾选 "双击关闭标签"

  • 本文向大家介绍升级到MySQL5.7后开发不得不注意的一些坑,包括了升级到MySQL5.7后开发不得不注意的一些坑的使用技巧和注意事项,需要的朋友参考一下 前言 前段时间,将线上MySQL数据库升级到了5.7。考虑到可能产生的不兼容性,在升级之前,确实也是战战兢兢,虽然测试环境,开发环境早在半年前就已提前升级。 基于前期的调研和朋友的反馈,与开发相关的主要有两点: sql_mode MySQL 5

  • 我有以下问题。 在一个类中,我声明: 有趣的是:currentVuln。Published.ToString()。这工作很好。 Published是声明为可空的日期时间属性,其方式如下: 问题是,在前面的方法中,currentVuln的打印值。Published.ToString()类似于18/07/2014 00:00:00(时间也包含在日期中)。 我只想显示日期,不想显示时间,所以我尝试使用类