本博文主要整理一些Go语言的特点,适宜于有go语法基础的同学,帮助大家一起扫盲golang,如需转载请联系作者
1.++,--
golang语法中,只有a++;a--; 不存在--a;++a语法
2.String
1. Go语言中的字符串以原生数据类型出现,使用字符串就像使用其他原生数据类型(int、bool、float32、float64 等)一样。
而Java中String不属于基本数据类型
2. 通过下标直接获取字符串中某个元素的值
例如:s:="abc" //s[0]=a
3.boolean
Go 语言中不允许将整型强制转换为布尔型.
布尔型无法参与数值运算,也无法与其他类型进行转换。
例如java执行下面的语句可以编译通过
if(1){System.out.println("条件为真")}
但是Golang执行对应的语句报错,错误信息为//non-bool 0 (type int) used as if condition
if(1){fmt.Println("条件为真")}
4.defer
defer 延迟调用
如果存在多个defer是,按照先进后出的顺序执行
5.数组比较
golang提供了数组比较的原生方法
num1 := [5]int{2, 2, 3, 4, 5}
num2 := [5]int{1, 2, 3, 4, 5}
num1 == num2 //相等为true,不相等为false
num1 != num2
6.切片
大家在学其他强类型编程语言时,多么渴望数组能够动态变化。Go语言中,就有切片可以解决,让您使用起来随心所欲;
切片,是解决数组的长度无法变化的利器,切片可进行拼接,长度自由等好处;
切片的本质是就是结构体
7.类型转换(特殊)
// 平常我们常见的类型转换格式:(类型)变量 ,int a; (float)a
// golang还有另外一种类型转换方式
userLogin, _ := bc.Get("user") // userLogin的类型:interface{}
u := userLogin.(*services.User) // 将userLogin 强转为User类型
8.结构体打印(类似java的toString()方法)
打印 Go 结构体(struct)信息:fmt.Printf("%+v", user)
代码:
package main
import "fmt"
// 用户
type User struct {
Id int
Name string
Age int
}
func main() {
user := User{Id:2, Name:"golang"}
// 打印 结构体
fmt.Printf("%+v", user)
// 输出换行符
fmt.Printf("\n")
// 判断实例是否为空
fmt.Println(user == User{})
}
输出:
{Id:2 Name:golang Age:0}
false
9.golang提供的MD5加密方法
https://studygolang.com/articles/2283
10.interface{}与struct
interface 针对方法的定义
struct 针对普通的数据结构定义
深入了解:https://www.cnblogs.com/zhangdewang/p/10612089.html
11.切片传参、map传参时原值会被修改,而结构体、普通数组传参时原值不会被改变。
形参所在函数中,切片参数使用append,凭拼接的数据对原数据不会有影响,下面会有提到。
// 切片、map作为参数传参时,在被传参的函数中修改值,会影响原函数中数据、map的值
// 以map举例
func main() {
m := map[int]string{1: "鱼儿", 2: "虾米"}
fmt.Println("传参前:", m)
update(m)
fmt.Println("传参后:", m)
}
func update(m map[int]string) {
m[1] = "鱼儿不存在"
}
**深度分析切片传参原值会被影响的原因**
/*
因为slice本质就是结构体,结构体里面有一个元素array 值指针类型(保存array的空间地址),作为参数传值时,其实就是传指针。如上函数举例:update方法实际就是获取array指针(array实际空间地址)进行操作,所以main函数打印时,发现原数据已经被修改。
*/
type slice struct {
array unsafe.Pointer
len int
cap int
}
12.指针*,与中括号[]的优先级
中括号[] 优先级高于 指针符号*
13.数组指针有P[0]的简写方式,切片指针没有p[0]的写法(区别)
func main() {
s := []int{1, 2, 3, 54}
var p *[]int
p = &s
fmt.Println(p)
fmt.Println(*p)
fmt.Println((*p)[0])
fmt.Println(p[0]) // 此处报错!数组指针有P[0]的简写方式,切片指针没有p[0]的写法
}
14.浅拷贝、深拷贝的概念
浅拷贝:仅仅考别的变量的值,没有对指向的空间进行任何的拷贝
深拷贝:将原有的变量的空间全部拷贝一份
15 .可以通过append方法对切片进行动态扩容,但是对原数据没有影响。但是通过不同的切片定义方式,使用append方法后,再修改原数据包含下标的数据,对原数据都是没有影响的。原因:当使用append()方法后,就会自动创建新的空间,所以对原数据没有影响
func main() {
//a := []int{1, 2, 3, 4, 5} //无论哪种切片的定义方式、无论空余cap多大,一旦涉及append,就会重新生成一个新的空间进行拼接
var a = make([]int, 2, 10) // 使用该方式定义切片,modify()修改的值会改变main()值;使用上面自动推导类型定义,modify()修改的值不会改变
a = []int{8, 9}
//fmt.Println("a2:", a2)
fmt.Println("原函数1", a)
modify(a)
fmt.Println("原函数2", a)
}
func modify(a1 []int) {
// 使用append进行动态扩容时,a的指向不再是主函数a的空间,而是指向新的空间
a1 = append(a1, 21) //注释该行代码,即可修改主函数中的数据
a1[0] = 111
fmt.Println(a1)
}
16.switch golang语法中的switch与java等其他语言的语法不太相同
查看https://www.jianshu.com/p/bb3cf84721ab
17.调用结构体的3种方式
// 方法值与方法表达式
type People struct {
id int
name string
}
func (p *People) PrintInfo() {
fmt.Println(*p)
}
func main() {
p := People{101, "小明"}
// 方式一:直接调用方法
p.PrintInfo()
// 方式二:方法值
f := p.PrintInfo //可以打印下f的类型
fmt.Printf("f的类型:%T\n", f)
f()
// 方式三:方法表达式
f_ := (*People).PrintInfo
f_(&p)
}
18.文件操作,写入数据(三种方式)
// 方式一:WriteString
n,err:=file.WriteString("Hello World")
// 方式二:Write
var str string="Hello World"
n,err:=file.Write([]byte(str))
// 方式三:WriteAt
n,err:=file.WriteAt([]byte(str),0)//第二个参数,off表示在指定的位置重置写入数据
// 获取文件的长度,通常与WriteAt的长度结合使用
file.Seek(offset,io.SeekEnd)//将光标定位到文件中原有内容的后面,返回文件中原有数据的长度。其中offset表示在yauncheng文件后面空出的长度
19.go也能开发桌面软件-go get github.com/lxn/walk
20.判断map中的key,value是否存在
/*
判断map中的key,value是否存在
*/
m11 := map[int]string{}
m11[1] = "123"
m11[2] = "223"
m11[3] = "323"
m11[100] = "423"
m11[5] = "523"
m11[6] = "623"
/*
注意重点:
以下方法可以判断该值是否存在,如果不存在,b为false,v为空
存在,b为true,v为值
*/
v, b := m11[1001]
fmt.Printf("%s", v)
fmt.Println(b)
//输出结果 :false
19.打印空字符串 %q
20.map 的delete ,如果该值不存在,不会报错。这是map的特性
21.结构体传参:
1.将结构体变量拷贝一份,传递。--几乎不用。内存消耗大,效率低
2.将结构体变量地址值,传递(传引用)。---使用频率非常高
3.unSafe.Sizeof(变量名)-->此种类型的变量所占用的内存空间大小
4.unSafe.Sizeof(指针):不管何总类型的指针,在64位操作系统下,大小一致。均为8字节!!!
22.结构体变量的比较:
1.比较:只能使用==和!= 不能> < >= <= ...
2.相同结构体类型(成员变量的类型、个数、顺序一致)变量之间可以直接赋值(注意:如果顺序不一致,就认为不是同一个结构体)
23.结构体指针做函数返回值:
1.不能返回局部变量的地址值---局部变量保存栈帧上,函数调用结束后,栈帧释放。
局部变量的地址,不再受系统保护,随时可能分配给其他程序。
2.可以返回局部变量的值。