nil
是 interface、function、pointer、map、slice 和 channel 类型变量的默认初始值。
string
类型的变量值不能为 nil
访问 map 中不存在的 key,会返回元素对应数据类型的零值,比如 nil、’’ 、false 和 0,取值操作总有值返回,故不能通过取出来的值来判断 key 是不是在 map 中。
string
类型的值是常量,不可更改。尝试使用索引遍历字符串,来更新字符串中的个别字符,是不允许的。( string 类型的值是只读的二进制 byte slice,如果真要修改字符串中的字符,将 string 转为 []byte 修改后,再转为 string 即可: )
// 更新字串的正确姿势:将 string 转为 rune slice(此时 1 个 rune 可能占多个 byte),直接更新 rune 中的字符
func main() {
x := "text"
xRunes := []rune(x)
xRunes[0] = '我'
x = string(xRunes)
fmt.Println(x) // 我ext
str := "hello 世界"
str1 := []rune(str)
for k, v := range str { // for range可以直接遍历带中文的字符串,因为for-range是按字符的方式遍历
fmt.Printf("%d=%c\n", k, v)
}
for i := 0; i < len(str1); i++ { // 0=h1=e2=l3=l4=o5= 6=世7=界,非for-range形式得转rune类型的切片,因为普通for是按字节遍历
fmt.Printf("%d=%c", i, str1[i])
}
}
内建函数len()
返回的是字符串的 byte 数量
在一个值为 nil 的 channel 上发送和接收数据将永久阻塞
struct、array、slice 和 map 的值比较可以使用相等运算符 == 来比较结构体变量,前提是两个结构体的成员都是可比较的类型
new()、make() 详解:https://www.cnblogs.com/kkbill/p/12540316.html
new()方法就是为 int/bool/struct 等值类型分配空间,返回相应类型的指针
go垃圾回收:https://www.bookstack.cn/read/For-learning-Go-Tutorial/src-spec-02.0.md
package main
import (
"fmt"
"unsafe"
"strconv"
)
// go的字符串不同,它是由字节组成的
// go语言中的字符使用utf-8编码,一个英文字母占一个字节,一个中文占3个字节
// 在go中字符的本质是一个整数,直接输出时,是该字符对应的utf-8编码的码值;字符类型可以进行运算
func main() {
var hh int = 10
fmt.Printf("type=%T, 占用字节: %d\n", hh, unsafe.Sizeof(hh)) // type=int, 占用字节: 8
var f float64 = 5.1234e-2 // = 5.1234/100
fmt.Println(f) // 0.051234
var ch byte = 'a' // 字符在ASCII码范围内,用byte类型比较好,比如:[0~9][a~z][A~Z]
fmt.Printf("type=%T, value=%v, 字符=%c\n", ch, ch, ch) // rune是int32的别名,值是ASCII码;%c按字符输出
var ch2 int = '南'
fmt.Printf("type=%T,unicode码值=%d \n",ch2,ch2) // type=int,unicode码值=21335(unicode的具体实现是utf-8)
var h uint8 = 97
fmt.Printf("%c\n", h) // a
zf := '南'+1
fmt.Println(zf)// 21336
// 基本数据类型转string
var boo bool
str := fmt.Sprintf("hello %d %c %f %t\n", hh, ch, f,boo)
fmt.Println(str) // hello 10 a 0.051234 false
str = strconv.FormatFloat(f,'f',10, 64) // float64转字符串,保留10位小数
fmt.Printf("str type %T, value=%q\n", str, str) // str type string, value="0.0512340000"
str = strconv.FormatBool(boo) // bool值转字符串
fmt.Printf("str type %T, value = %q\n", str, str) // str type string, value = "false"
str = strconv.Itoa(hh) // int类型转字符串
fmt.Printf("str type %T, value=%q\n", str, str) // str type string, value="10"
var s1 string = "true"
var bool1 bool
bool1,_ = strconv.ParseBool(s1)
fmt.Printf("%T : %v\n",bool1, bool1) // bool : true
}
值类型
: int系列,float系列,bool, string, 数组, 结构体
引用类型
: 指针, 切片, map, chan, interface
值类型: 变量直接存储值,内存通常在栈中分配
引用类型: 变量存储的是一个地址,这个地址对应的空间才真正存储数据(值),内存通常在堆上分配,当没有任何变量引用这个地址时,该地址对应的数据空间就成为一个垃圾,由GC来回收
package main
import (
"fmt"
)
func main() {
var f2 float32
var f3 float32
var f4 float32
var f5 float32
f4 = 10
f5 = f4 / 4
f3 = 10.0 / 4 // 如果我们希望保留小数部分,则需要有浮点数参与运算
f2 = 10 / 4 // 如果运算的数都是整数,那么除后,去掉小数部分,保留整数部分
fmt.Println(f2, f3, f5) // 2 2.5 2.5
fmt.Println(-10 % -4) // 输出-2; a%b = a-a/b*b=-10-(-10/-4*-4)=-2
// 不使用第3个变量,交换两个变量的值
a, b := 3, 4
a = a + b
b = a - b // (a+b)-b=a
a = a - b // (a+b)-(a+b-b)=b
fmt.Println(a, b) // 4, 3
}
package main
import (
"fmt"
)
// 10进制转其他进制
func main() {
var int1 int = 5
fmt.Printf("%d=%b\n", int1, int1) // 5=101; %b输出为二进制
// 八进制: 0~7, 满8进1,以数字0开头表示
var int2 = 011
fmt.Println("int2=", int2) // int2= 9; 011对应的10进制数是9
// 八进制转10进制:从最低位开始,右边的,将每个位上的数提取出来,乘以8的(位数-1)次方,然后求和
var int4 = 0123 // 0123 = 3乘以8的0次方 + 2*8的1次方 + 1*8的2次方=83
fmt.Println("int4=", int4) // int4= 83
// 十六进制: 0-9 及 a-f, 满16进1, 以 0x 或 0X 开头表示(不区分大小写)
var int3 int = 0x11
fmt.Println("int3=", int3) // int3= 17; 0x11对应的十进制数是17
// 十六进制转10进制:从最低位开始,将每个位上的数提取出来,乘以16的(位数-1)次方,然后求和
var int5 int = 0x34A // 0x34A = 10*16的0次方 + 4*16 + 3*16*16=842
fmt.Println("int5=", int5)
}