06 | 程序实体的那些事儿 (下)
package main
import ."fmt"
var container = []string{"0","1","2"}
func main() {
container := map[int]string{0:"zero",1:"one",2:"two"}
//输出one
Println(container[1])
}
如何判断container类型
value,ok := interface{}(container).([]string)
它包括了用来把container变量的值转换为空接口值的interface{}(container)。 (如果container是接口类型,直接是
container.([]string))
以及一个用于判断前者的类型是否为切片类型 []string 的.([]string)。
如果ok是true,那么被判断的值将会被自动转换为[]string类型的值,并赋给变量value,否则value将被赋予nil(即“空”)。
interface{}代表空接口,任何类型都是它的实现类型,任何类型的值都可以很方便地被转换成空接口的值
一对不包裹任何东西的花括号,除了可以代表空的代码块之外,还可用于表示不包含任何内容的数据结构(或者说数据类型)。
package main
import (
"fmt"
)
var container = []string{"zero", "one", "two"}
func main() {
container := map[int]string{0: "zero", 1: "one", 2: "two"}
// 方式1。
_, ok1 := interface{}(container).([]string)
_, ok2 := interface{}(container).(map[int]string)
if !(ok1 || ok2) {
fmt.Printf("Error: unsupported container type: %T\n", container)
return
}
fmt.Printf("The element is %q. (container type: %T)\n",
container[1], container)
// 方式2。
elem, err := getElement(container)
if err != nil {
fmt.Printf("Error: %s\n", err)
return
}
fmt.Printf("The element is %q. (container type: %T)\n",
elem, container)
}
func getElement(containerI interface{}) (elem string, err error) {
switch t := containerI.(type) {
case []string:
elem = t[1]
case map[int]string:
elem = t[1]
default:
err = fmt.Errorf("unsupported container type: %T", containerI)
return
}
return
}
数字与字符转换
package main
import (
"fmt"
"strconv"
)
func main() {
fmt.Println(string(-1))
a := 97
fmt.Println(string(a))
as := strconv.Itoa(a)
fmt.Println(string(as))
//输出结果
//�
//a
//97
}
07 | 数组和切片
数组长度一定,切片长度会随着元素增加而增加,但长度不会减少
Go 中数组赋值和函数传参都是值复制的
引用类型:切片,字典,通道,函数类型等
值类型:基础数据类型,结构体类型
判断是值传递还是引用传递,只需要看他的类型就行了。
//len = cap = 8
s3 := []int{1, 2, 3, 4, 5, 6, 7,8}
//[3,6)
// len = 3
//cap = 8 - 3 = 5 (可以向右扩展的长度,因为起始索引是3 所以减3)
s4 = s3[3:6]
扩容问题
08 | container包中的那些容器
list与ring 看源码
09 | 字典的操作和约束
键不能是函数,字典,切片类型 因为键要支持 == 判断
如果是interface 键类型具体赋值是以上3中类型 会引发panic
哈希桶里的结构是,“键的哈希值-内部结构”对的集合,这个内部结构的结构是“键1元素1键2元素2键3元素3”,是一块连续的内存。在通过键的哈希值定位找到哈希桶和那个“键的哈希值-内部结构”对之后,就开始在这个内部结构里找有没有这个键
非原子操作需要加锁, map并发读写需要加锁,map操作不是并发安全的,判断一个操作是否是原子的可以使用 go run race 命令做数据的竞争检测
10 | 通道的基本操作
通道之前取值和放入值都是并行的
package main
func main() {
// 示例1。
ch1 := make(chan int, 1)
ch1 <- 1
//ch1 <- 2 // 通道已满,因此这里会造成阻塞。
// 示例2。
ch2 := make(chan int, 1)
//elem, ok := <-ch2 // 通道已空,因此这里会造成阻塞。
//_, _ = elem, ok
ch2 <- 1
// 示例3。
var ch3 chan int
//ch3 <- 1 // 通道的值为nil,因此这里会造成永久的阻塞!
//<-ch2 // 通道的值为nil,因此这里会造成永久的阻塞!
_ = ch3
}
通道接收方可以有两个参数,第一个表示值,第二个是bool类型 表示通道是否关闭
接收方在通道关闭后 任然可以接收到存在于通道里的数据,由于这个特性,关闭通道最好在发送方关闭