初学者学习golang可能遇到的坑
我也是个golang初学者,刚入门的话,有些“坑”还是不好发现的。如map只是定义了然后就拿来使用,变量的值覆盖等。
本来打算写一篇的,后面发现有人写的挺不错的,我就把里面的有些坑都记录了下,每个都试验了下,也可以防止自已遇到这些问题的时候,不知从何下手。
参考自博客:https://www.cnblogs.com/276815076/p/8583589.html ,在此对作者表示感谢。但我没有完全照搬代码,每个代码都自已敲的。只是概念有参考。如有侵权,请告知
1 和其它语言不太一样 ," { "不能单独成一行,每个语句也不必加上分号
package main
import "fmt"
//错误
func main()
{
fmt.Println("Hello,World");
}
会报错:
# command-line-arguments
./firstlearn.go:5:6: missing function body
./firstlearn.go:6:1: syntax error: unexpected semicolon or newline before {
//正确
func main(){
fmt.Println("Hello,World")
}
2 定义了变量,但未使用
如果定义了变量,又没有使用则是编译不通过的
全局变量例外
仅仅是给变量赋值也不叫使用,仍然需要在某处使用它,比如输出出来
package main
import "fmt"
var globalVal = 10 //全局变量,定义了可以不使用
//a定义了,但未使用,会报错 :a declared and not used
func defineNotUsed() {
var a int
}
//b有赋值,但是末使用。如输出
func valueNotUsed() {
b := 3
}
func main(){
defineNotUsed()
valueNotUsed()
}
//正确
package main
import "fmt"
var globalVal = 10 //全局变量,定义了可以不使用
func defineNotUsed() {
var a int
fmt.Println(a)
}
func valueNotUsed() {
b := 3
fmt.Println(b)
}
func main(){
defineNotUsed()
valueNotUsed()
}
3 变量定义赋值符(:=)对同一变量只能使用一次
:=为变量同时定义及赋值,不可使用多次
在result,err := show() 这种语法中要注意,防止重复赋值
package main
import "fmt"
func main(){
a := 10
a := 20 //错误,a上面已经定义且赋值了,不可重复
fmt.Println(a)
}
//正确
package main
import "fmt"
func main(){
a := 10
a = 20 // :=已经定义了,后续操作直接赋值就行
fmt.Println(a)
}
4 定义赋值符,只能在函数外部使用
package main
import "fmt"
a :=3 //定义赋值操作符,不能在外面使用,外面只能用var定义
func main(){
fmt.Println(a)
}
//正确
package main
import "fmt"
func main(){
a :=3 //只能在内部使用这种操作符
fmt.Println(a)
}
5 struct成员变量不能使用简短操作符 := ,需要使用预定义变量
package main
import "fmt"
type person struct {
Name string
Age int
}
func showPersion() (string,error){
return "lc",nil
}
func main(){
var p person
p.Name,err := showPersion() //p.Name为struct的字段,不能直接使用 :=,需要用预定义实现
if err != nil {
return
}
fmt.Println(p)
}
// 正确
func main(){
var p person
var err error //使用预定义
p.Name,err = showPersion() //这里改为直接=,不能用 :=
if err != nil {
return
}
fmt.Println(p)
}
6 小心变量被覆盖
package main
import "fmt"
func change(a int){
fmt.Println(a)
}
func main(){
a :=1
change(a)
{
a :=2 //这里 a的作用域只在函数内部, 除非用 a = 2就会改变
fmt.Println(a)
}
change(a)
}
//输出为 1 2 1
7 显示类型无法用 nil初始化
package main
import "fmt"
func main() {
var a []string = nil
var b map[string]string = nil
var c = nil //c不知道是什么类型,无法用nil初始化 ,a,b可以
_ = b
fmt.Println(a, b)
}
8 直接使用值为nil的slice和map
slice,map刚定义时,值为nil不能直接使用
package main
import "fmt"
func sliceTest() {
var s1 []string
//s1 = []string{"aa"}
//s1[0]= "a"
//s1 = append(s1,"b")
fmt.Println(s1[0]) //会报超出范围错误:index out of range,需要赋值或用append添加
}
func mapTest() {
var m map[string]string
m["name"] = "lc" //会报错 ,m是值为nil的map:assignment to entry in nil map
fmt.Println(m["name"])
}
func main() {
sliceTest()
mapTest()
}
//正确
package main
import "fmt"
func sliceTest() {
var s1 []string
s1 = []string{"aa"}
//s1[0]= "a"
//s1 = append(s1,"b")
fmt.Println(s1[0])
}
func mapTest() {
//var m map[string]string
m := make(map[string]string) //用make来声明
m["name"] = "lc"
fmt.Println(m["name"])
}
func main() {
sliceTest()
mapTest()
}
9 map不能像slice一样,使用cap检测容量大小
package main
import "fmt"
func main() {
m := make(map[string]int)
m["a"] = 10
fmt.Println(m,cap(m))
}
10 slice中,cap和len的区别
cap容量,当超过容量时,会自动扩容
len 实际大小
package main
import (
"fmt"
"reflect"
)
func main() {
s := make([]string,10)
s[0] = "a"
s[1] = "a"
s[2] = "a"
s[3] = "a"
s[4] = "a"
s[5] = "a"
s[6] = "a"
s[7] = "a"
s[8] = "a"
s[9] = "a"
s = append(s,"bbb")
fmt.Println(cap(s),len(s))
}
//输出: 20 ,11
11 string类型的变量,值不能为nil
package main
import "fmt"
func main() {
var s string = nil
if s == nil {
fmt.Println("empty string")
}
}
//正确
package main
import "fmt"
func main() {
var s string
if s == "" {
fmt.Println("empty string")
}
}
12 golang中数组作函数参数,默认值传递,修改的数据不会影响原始数组,如要实现,可以
将数组以指针接受
使用slice
package main
import "fmt"
func arrayChange(a [3]int) {
a[2] =3
fmt.Println(a)
}
func main() {
var a = [...]int{3,4,5}
arrayChange(a)
fmt.Println(a)
}
//输出
[3 4 3]
[3 4 5]
并不会改变原数组,
可使用指针
func arrayChange(a *[3]int) {
a[2] =3
fmt.Println(a)
}
func main() {
var a = [...]int{3,4,5}
arrayChange(&a)
fmt.Println(a)
}
或slice
func arrayChange(a []int) {
a[2] =3
fmt.Println(a)
}
func main() {
var a = []int{3,4,5}
arrayChange(a)
fmt.Println(a)
}
13 混淆了slice的返回值,for会返回二个值,第一个值索引,第二个才是值
func main() {
var a = []string{"a","b","c"}
for v := range a {
fmt.Println(v)
}
}
//输出0 1 2
func main() {
var a = []string{"a","b","c"}
for _, v := range a {
fmt.Println(v)
}
}
用_去掉索引,输出 a b c
** 14 访问map未定义的key**
通过第二个返回值来区分
func main() {
a := map[string]string{"a":"aa", "b":"bb"}
if _,ok := a["c"]; !ok {
fmt.Println( "not found")
}
15 strings是常量,不可更改
转成rune slice后更改
func main() {
s := "Hello"
//s[0] = "W"
fmt.Println(s)
//转成rune slice
sRune := []rune(s)
sRune[0] = '世' //注意这里是单引号
sRune[1] = '界' //注意这里是单引号
s = string(sRune)
fmt.Println(s,len(s))
}
16 字符串的长度
len()返回的是字符的byte数量,而不是字符数
utf8的RuneCountInString,返回字符数
func main() {
s := "Hello兴"
fmt.Println(len(s))
fmt.Println(utf8.RuneCountInString(s))
}
**17 多行map,slice,array后的语句缺少 “,”号 **
package main
func main() {
a :=[]int{1,2} // 单行后 '}' ,尾部的 " , " 号非必须。
b :=[]int{1,2 //多行后,尾部的 ","为必须。
}
}
18 不导出的struct字段,无法被encode
首字母为小写的字段为无法导出字段
func main() {
type person struct {
Name string
age int
}
p :=&person{"lc",3}
e, _ := json.Marshal(p)
fmt.Println(string(e))
var o person
json.Unmarshal(e,&o)
fmt.Printf("%#v\n", o)
}
19 slice,map,array通过range来更新元素
无法通过引用来更新元素
使用索引访问来更新元素
func main() {
//无法通过引用更新
a :=[]int{1,2,3}
for _,v := range a {
v = v * 10
}
fmt.Println(a)
//使用索引更新
b :=[]int{1,2,3}
for i,v := range b {
b[i] = v * 10
}
fmt.Println(b)
}
20从slice切出新slice时,会引用原来的slice数组,造成大量的 内存使用
不要重新切新的slice
使用临时拷贝
func main() {
s := make([]int,10)
fmt.Println(s,len(s),cap(s))
//从原slice中切出新slice会导致指向原来的底层数组,重新分配
c :=s[:3]
fmt.Println(c,len(c),cap(c))
//通过拷贝临时slice的数据,而不是重新切片
t :=make([]int,3)
copy(t,s)
fmt.Println(t,len(t),cap(t))
}
// 输出
[0 0 0 0 0 0 0 0 0 0] 10 10
[0 0 0] 3 10
[0 0 0] 3 3
21 从一个slice创建新slice时,注意“旧”数据问题
func main() {
s1 := []int{1,2,3}
fmt.Println(s1,len(s1),cap(s1))
s2 :=s1[1:]
fmt.Println(s2,len(s2),cap(s2))
//以上s1,s2指向同一个slice
//继续往 s2追加s2
s2 = append(s2,4) //导致分配新的容量,和 s1没关系了
for i,v := range s2 {
s2[i] = v * 10
}
fmt.Println(s1,len(s1),cap(s1)) //s1指向的还是旧的slice
fmt.Println(s2,len(s2),cap(s2))
}
初学者学习golang可能遇到的坑的更多相关文章
- Golang的防坑小技巧
Golang的防坑小技巧 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 作为一名小白,在之前没有接触到编程的小伙伴,难免会踩到一些坑,比如说刚刚入门的时候你需要安装环境,学习Gol ...
- 开源一个完整的iOSApp《丁丁美图》供初学者学习
学习iOS开发的时候,得益于开源社区的大量开源项目,去年开始购买了个人开发者账号,写了这个练手项目<丁丁美图>,并上传到了App Store(Ipad版本被驳回也懒得处理).现在将代码开源 ...
- .NET平台技术体系梳理+初学者学习路径推荐+我们的愿景与目标
文章出自:http://www.cnblogs.com/ice-river/p/3475041.html 一 .NET平台技术体系梳理 .NET平台应用领域众多(桌面开发,web开发,移动开发),不断 ...
- Golang中的坑二
Golang中的坑二 for ...range 最近两周用Golang做项目,编写web服务,两周时间写了大概五千行代码(业务代码加单元测试用例代码).用Go的感觉很爽,编码效率高,运行效率也不错,用 ...
- Golang 中的坑 一
Golang 中的坑 短变量声明 Short variable declarations 考虑如下代码: package main import ( "errors" " ...
- MHA-Failover可能遇到的坑
一.主从数据一致性 1.1.如何保证主从数据一致性 参考叶师傅文章:FAQ系列 | 如何保证主从复制数据一致性 在MySQL中,一次事务提交后,需要写undo.写redo.写binlog,写数据文件等 ...
- 跟初学者学习IbatisNet第二篇
在上一篇里面我们知道了什么是IbatisNet,并且知道了如何用IbatisNet进行简单的增删改查的操作,在这一篇文章里面我们主要介绍一下IbatisNet操作存储过程. 我们一般把存储过程分为两种 ...
- 学习Golang语言(6):类型--切片
学习Golang语言(1): Hello World 学习Golang语言(2): 变量 学习Golang语言(3):类型--布尔型和数值类型 学习Golang语言(4):类型--字符串 学习Gola ...
- 初学者学习JavaScript的实用技巧!
Javascript是一种高级编程语言,通过解释执行.它是一门动态类型,面向对象(基于原型)的直译语言.它已经由欧洲电脑制造商协会通过ECMAScript实现语言标准化,它被世界上的绝大多数网站所使用 ...
随机推荐
- 上云测试,这些关键点你get 到没有
导读,先从云化说起,再谈谈云化形态下,除了常规的功能测试,云化的测试,还需要有几个必须要get到的硬核指标,最后在分别详解这些关键点硬核指标是什么,和如何测试呢.这是个值得深思的问题,希望所有测试人都 ...
- 防止ARP欺骗
前言: 曾经因为宿舍里面的同学经常熬夜打游戏,好言相劝不管用,无奈之下使用arp欺骗他们的主机,使之晚上11点之后游戏延迟,掉线,最后,一到11点同学们就都上床睡觉了. 防止arp欺骗的三种思路: 在 ...
- 201871010112-梁丽珍《面向对象程序设计(java)》第十周学习总结
项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...
- Nginx配置参数中文详细说明
#定义Nginx运行的用户和用户组user www www;##nginx进程数,建议设置为等于CPU总核心数.worker_processes 8;##全局错误日志定义类型,[ debug | in ...
- HTML与CSS学习笔记(2)
1.CSS背景样式? background-color 背景色 background-image 背景图 url(背景地址) 默认:会水平垂直铺满背景图 background-repeat 平铺方式 ...
- centos用手机号无法登入安全狗的解决方法
前面我们安装好了安全狗,需要加服务器加入服云中,通常用sdcloud –u 用户名就可以,但如果是手机号的话就可能无法登陆,我们用sdcloud -h命令查看帮助,如下图所示 我们看到输入账号可以用- ...
- 配置nginx 支持php
一.确保php-fpm已经启动: ps -A | grep php-fpm 如果没有启动,则启动php-fpm: /usr/local/sbin/php-fpm 查看是否启动成功: root@iZ25 ...
- linux中以.d结尾的目录
一般为了保持对原有配置方式的兼容,而增加的.d结尾目录. 如: /etc/X11/xorg.conf 这原本是个文件,现在也有了一个/etc/X11/xorg.conf.d这样的目录,显卡驱动的相关设 ...
- WebJars简介 —— 前端资源的jar包形式(以后接触到再深入总结)
对于日常的web开发而言,像css.js.images.font等静态资源文件管理是非常的混乱的.比如jQuery.Bootstrap.Vue.js等,可能每个框架使用的版本都不一样.一不注意就会出现 ...
- 11/9 <Stack> 155 232 225
155. Min Stack class MinStack { int min = Integer.MAX_VALUE; Stack<Integer> stack = new Stack& ...