字符串
使用双引号或反引号引起来的任意个字符。它是字面常量。
func main() {
var a = "abc\n测试" // \n换行
fmt.Println(a)
}
abc
测试
func main() {
var a = "abc\n\t测试" \\换行后在tab
fmt.Println(a)
}
abc
测试
func main() {
var a = `abc
测试` \\ ``反引号 反引号内不支持转义字符
fmt.Println(a)
}
abc
测试
func main() {
var a = `json:"name"` // 字符串里面如果有双引号,使用反引号定义方便,不用使用转义符 直接使用反引号更加方便 "json:\"name\"" 等价 `json:"name"`
fmt.Println(a)
}
json:"name"
func main() {
var a = "abc" + "efg"
fmt.Println(a)
}
abcefg
字符串格式化
一般在输出fmt.Printf("%+v\n", fmt)
- %v 适合所有类型数据,调用数据的缺省打印格式\
- %+v对于结构体,会多打印出字段名
- %#v 对于结构体,有更加详细的输出
- %T 打印值的类型
- %% 打印百分号本身
整数
- %b 二进制;%o 八进制;%O 八进制带0o前缀;%x 十六进制小写;%X16 进制大写
- %U 把一个整数用Unicode格式打印。例如 fmt.Printf("%U, %x, %c\n", 27979, 27979,
27979) 输出 U+6D4B, 6d4b - %c 把rune、byte的整型值用字符形式打印
- %q 把一个整型当做Unicode字符输出,类似%c,不过在字符外面多了单引号。q的意思就是quote
浮点数 - %e、%E 科学计数法
- %f、%F 小数表示法,最常用
- %g 内部选择使用%e还是%f以简洁输出;%G 选择%E或%F
字符串或字节切片
- %s 字符串输出。如果是rune切片,需要string强制类型转换
- %q 类似%s,外部加上双引号。q的意思就是quote
指针
- %p 十六进制地址
输出函数
输出到标准输出
- Print:使用缺省格式输出,空格分割
- Println:使用缺省格式输出,空格分割,最后追加换行
- Printf:按照指定的格式符输出
输出到字符串,经常用来拼接字符串用
- Sprint:相当于Print,不过输出为string
- Sprintln:相当于Println,不过输出为string
- Sprintf:相当于Printf,不过输出为string
操作符
逻辑运算真值表
理解:
与逻辑相当于乘法:A×B=F
或逻辑相当于加法:A+B=F,但是 不是二进制,不往上进位
非逻辑:取反
算数运算符
func main() {
var a = 5 / 2 //2 除法
fmt.Printf("%v\n", a)
}
func main() {
var a = 5 % 2 //1 取余
fmt.Printf("%v\n", a)
}
++、--只能是i++、i--,且是语句,不是表达式。也就是说,语句不能放到等式、函数参数等地方。例
如, fmt.Println(a++) 是语法错误。
没有++i、--i。
常量计算问题
常量分为typed类型化常量和untyped常量
类型不同 不能进行计算
var a int = 1
var b float32 = 2.3
fmt.Println(a * b) // 错误,int和float32类型不同 需要进行强制类型转换
但是
fmt.Println(1 * 2.3) 不报错
因为根据语法糖 1已经被隐式类型转换为float64类型
fmt.Println(1 * 2.3)
fmt.Printf("%T %[1]g\n", 1*2.3) //%g是float的类型
2.3
float64 2.3
位运算符
&位与、|位或、^异或、&^位清空、<<、>>
2&1, 2&^1, 3&1, 3&^1
&^1 代表的意思是将1的位置对应的全列全部清空为0 其他位上面的数值直接落下去
^异或 转化为2进制后相同的位位0 不同的位为1
a: 00001100
b:00000100
c: 00001000
2&1 2&^1 3&1 3&^1
10 10 11 11
01 相乘为0 00 直接成为10 为2 01 相乘转换10进制 为1 01
10 为2
2|1, 3^3, 1<<3 ,16>>3 , 2^1
2|1 3^3 3&1
10 11 11
01 相加为11 转换为10进制为3 11 01
00 转换为10进制为0 01
1<<3
位号向左移动3位
1
1000 转换为10进制为8 我的理解是向左移动就是乘法 移动几位就是几次方 2^3=8
16>>3
向左移动3位
10000
00010 转换为10进制 就是2 同样的 左移动就是除 16/(2^3)=2
x&y ,位与本质就是按照y有1的位把x对应位的值保留下来。
x&^y,位清空本质就是先把y按位取反后的值,再和x位与,也就是y有1的位的值不能保留,被清空,原
来是0的位被保留。换句话说,就是按照y有1的位清空x对应位。
比较运算符
比较运算符组成的表达式,返回bool类型值。成立返回True,不成立返回False
==、!=、>、<、>=、<=
1 && 5 > 3 在go中,不可以用逻辑运算符来计算非bool型
在其他语言中,可以做某些类型值等效看做bool值。在逻辑运算中,1看做真true,0看做false,-1看做真;""看做false,非空字符串看做true
短路
逻辑运算符
&&、||、!
短路
true || false || false || false 为true || 一真则真
false || true || false || false 为true
false && true && false && true 为false && 一假则假
true || false && true 为true
5 > 3 && "abc" < "xyz" 逻辑运算符两边必为bool类型
指针操作
数据是放在内存中,内存是线性编址的。任何数据在内存中都可以通过一个地址来找到它。
标识符的本质,指向,编译后被翻译成内存地址
是一种类型的值,本质上是一个大整数,简单认为整个整数就是内存中的门牌号码
*int 指向int类型数据的指针
0xc000018088 表示门牌号码
门里面房间里面住着数据
&是取地址 内存的存放位置
*指针变量,通过指针取值
func main() {
a := 101
b := &a
fmt.Printf("%T %[1]v\n", b)
}
*int 0xc00001a098 b的类型是int类型
c := *b
fmt.Printf("%+v\n", c) //c 101
但是在这里c的地址是否和a的地址相同
答案是不同的 这里相当于a创建了一个副本101 这个副本在内存中有个独立的位置 而c指向的是这个内存
更加清晰的理解就是 取到了101的值 在定义赋值给c 那初始化赋值不就是重新开辟新的内存地址
func main() {
a := 101
b := &a
fmt.Printf("%T %[1]v\n", b)
c := *b
fmt.Printf("%v\n", &c)
}
*int 0xc00001a098
0xc00001a0b8
func main() {
a := 101
b := &a
c := *b
fmt.Println(1, a == c)
fmt.Println(2, b == &c)
fmt.Println(b, &b, c, &c)
}
1 true
2 false
0xc00001a098 0xc00000a028 101 0xc00001a0b0
func main() {
a := 101
b := &a
c := *b
fmt.Println(1, a == c)
fmt.Println(2, b == &c)
fmt.Println(b, &b, c, &c)
var d = a
fmt.Println(3, d == a)
fmt.Println(4, &d == &a, &a, &d)
}
1 true
2 false
0xc00001a088 0xc00000a028 101 0xc00001a0a0
3 true
4 false 0xc00001a088 0xc00001a0d0
只要用指针取值 必定会重新创建一个新的内存地址
fmt.Println(1, a == c)
fmt.Println(2, b == &c)
fmt.Println(b, &b, c, &c)
var d = a
fmt.Println(3, d == a)
fmt.Println(4, &d == &a, &a, &d)
}
1 true
2 false
0xc00001a088 0xc00000a028 101 0xc00001a0a0
3 true
4 false 0xc00001a088 0xc00001a0d0
只要用指针取值 必定会重新创建一个新的内存地址