目录

代码理解及纠错

1、defer和panic执行先后顺序

package main

 import (
"fmt"
) func main() {
defer_call()
} func defer_call() {
defer func() { fmt.Println("打印前") }()
defer func() { fmt.Println("打印中") }()
defer func() { fmt.Println("打印后") }()
panic("触发异常")
}
    打印后
打印中
打印前
panic: 触发异常

defer 的执行顺序是后进先出。当出现 panic 语句的时候,会先按照 defer 的后进先出的顺序执行,最后才会执行panic

2、for循环元素副本问题

func main() {

     slice := []int{0,1,2,3}
m := make(map[int]*int) for key,val := range slice {
m[key] = &val // 正确写法
// value := val
// m[key] = &value
} for k,v := range m {
fmt.Println(k,"->",*v)
}
}
    0 -> 3
1 -> 3
2 -> 3
3 -> 3

这是新手常会犯的错误写法,for range 循环的时候会创建每个元素的副本,而不是元素的引用,所以 m[key] = &val 取的都是变量 val 的地址,所以最后 map 中的所有元素的值都是变量 val 的地址,因为最后 val 被赋值为3,所有输出都是3

3、slice追加元素问题

// 1.
func main() {
s := make([]int, 5)
s = append(s, 1, 2, 3)
fmt.Println(s)
} // 2.
func main() {
s := make([]int,0)
s = append(s,1,2,3,4)
fmt.Println(s)
}

两段代码分别输出:

    [0 0 0 0 0 1 2 3]
[1 2 3 4]

append 向 slice 添加元素,第一段代码常见的错误是 [1 2 3],需要注意。

4、返回值命名问题

    // 第二个返回值未命名错误
func funcMui(x,y int)(sum int,error){
return x+y,nil
}

在函数有多个返回值时,只要有一个返回值有命名,其他的也必须命名。如果有多个返回值必须加上括号();如果只有一个返回值且命名也必须加上括号()。这里的第一个返回值有命名 sum,第二个没有命名,所以错误。

5、用new初始化内置类型问题

func main() {
list := new([]int)
list = append(list, 1)
fmt.Println(list)
}

不能通过编译,new([]int) 之后的 list 是一个 *[]int 类型的指针,不能对指针执行 append 操作。可以使用 make() 初始化之后再用。同样的,map 和 channel 建议使用 make() 或字面量的方式初始化,不要用 new() 。

6、切片append另外一个切片问题

func main() {
s1 := []int{1, 2, 3}
s2 := []int{4, 5}
s1 = append(s1, s2)
fmt.Println(s1)
}

不能通过编译。append() 的第二个参数不能直接使用 slice,需使用 … 操作符,将一个切片追加到另一个切片上:append(s1,s2…)。或者直接跟上元素,形如:append(s1,1,2,3)。

7、全局变量用:=声明问题

var(
size := 1024
max_size = size*2
) func main() {
fmt.Println(size,max_size)
}

:=只能在函数内部使用

8、结构体比较问题

func main() {
sn1 := struct {
age int
name string
}{age: 11, name: "qq"}
sn2 := struct {
age int
name string
}{age: 11, name: "qq"} if sn1 == sn2 {
fmt.Println("sn1 == sn2")
} sm1 := struct {
age int
m map[string]string
}{age: 11, m: map[string]string{"a": "1"}}
sm2 := struct {
age int
m map[string]string
}{age: 11, m: map[string]string{"a": "1"}} if sm1 == sm2 {
fmt.Println("sm1 == sm2")
}
}

编译不通过 invalid operation: sm1 == sm2;

  • 结构体只能比较是否相等,但是不能比较大小。
  • 相同类型的结构体才能够进行比较,结构体是否相同不但与属性类型有关,还与属性顺序相关
  • 如果 struct 的所有成员都可以比较,则该 struct 就可以通过 == 或 != 进行比较是否相等,比较时逐个项进行比较,如果每一项都相等,则两个结构体才相等,否则不相等;

那什么是可比较的呢,常见的有 bool、数值型、字符、指针、数组等。像切片、map、函数等是不能比较的。 具体可以参考 Go 说明文档。

9、iota的使用

const (
x = iota
_
y
z = "zz"
k
p = iota
) func main() {
fmt.Println(x,y,z,k,p)
}

编译通过,输出:0 2 zz zz 5。知识点:iota 的使用.

  • 每次 const 出现时,都会让 iota 初始化为0
  • iota出现后,下面的变量无初始值,会按照iota自增长
  • 下划线_可以跳过该行iota的增长,iota还是按行增长的,知道遇到不为const和_的其他变量

10、接口类型断言使用

func GetValue() int {
return 1
} func main() {
i := GetValue()
switch i.(type) {
case int:
println("int")
case string:
println("string")
case interface{}:
println("interface")
default:
println("unknown")
}
}

编译失败。考点:类型选择,类型选择的语法形如:i.(type),其中 i 是接口,type 是固定关键字,需要注意的是,只有接口类型才可以使用类型选择。

11、不同类型相加问题

func main() {
a := 5
b := 8.1
fmt.Println(a + b)
}

a 的类型是 int,b 的类型是 float,两个不同类型的数值不能相加,编译报错。可以使用类型强转来相加

12、数组类型比较问题

func main() {
a := [2]int{5, 6}
b := [3]int{5, 6}
if a == b {
fmt.Println("equal")
} else {
fmt.Println("not equal")
}
}

Go 中的数组是值类型,可比较,另外一方面,数组的长度也是数组类型的组成部分,所以 a 和 b 是不同的类型,是不能比较的,所以编译错误。

13、map删除不存在的值和获取不存在的值

func main() {
s := make(map[string]int)
delete(s, "h")
fmt.Println(s["h"])
}

删除 map 不存在的键值对时,不会报错,相当于没有任何作用;获取不存在的减值对时,返回值类型对应的零值,所以返回 0。

14、格式化输出问题

func main() {
i := -5
j := +5
fmt.Printf("%+d %+d", i, j)
}

%d表示输出十进制数字,+表示输出数值的符号。

15、结构体优先调用外层方法

type People struct{}

func (p *People) ShowA() {
fmt.Println("showA")
p.ShowB()
}
func (p *People) ShowB() {
fmt.Println("showB")
} type Teacher struct {
People
} func (t *Teacher) ShowB() {
fmt.Println("teacher showB")
} func main() {
t := Teacher{}
t.ShowB()
}

外部类型通过嵌套可以继承内部结构体的方法,外部类型还可以定义自己的属性和方法,甚至可以定义与内部相同的方法,这样内部类型的方法就会被“屏蔽”。这个例子中的 ShowB() 就是同名方法。

16、defer参数传递副本

func hello(i int) {
fmt.Println(i)
}
func main() {
i := 5
defer hello(i)
i = i + 10
}

这个例子中,hello() 函数的参数在执行defer语句的时候会保存一份副本,在实际调用 hello() 函数时用,所以是输出5

17、字符串只读

func main() {
str := "hello"
str[0] = 'x'
fmt.Println(str)
}

Go 语言中的字符串是只读的。所以编译错误compilation error

18、整数强转字符串

func main() {
i := 65
fmt.Println(string(i))
}

UTF-8 编码中,十进制数字 65 对应的符号是 A。输出A

19、切片长度问题

func main() {

    s := [3]int{1, 2, 3}
a := s[:0]
b := s[:2]
c := s[1:2:cap(s)]
}

a长度是0,容量是3;

b长度是2,容量是3;

c长度是1,容量是2;cap(s)虽然是3,但是子切片的容量不能大于底层数组的长度

截取操作有带 2 个或者 3 个参数,形如:[i:j] 和 [i:j:k],假设截取对象的底层数组长度为 l。在操作符 [i:j] 中,如果 i 省略,默认 0,如果 j 省略,默认底层数组的长度,截取得到的切片长度和容量计算方法是 j-i、l-i。操作符 [i:j:k],k 主要是用来限制切片的容量,但是不能大于数组的长度 l,截取得到的切片长度和容量计算方法是 j-i、k-i。

20、闭包引用和匿名函数问题

type Person struct {
age int
} func main() {
person := &Person{28} // 1.
defer fmt.Println(person.age) // 2.
defer func(p *Person) {
fmt.Println(p.age)
}(person) // 3.
defer func() {
fmt.Println(person.age)
}() person.age = 29
}

1.person.age 此时是将 28 当做 defer 函数的参数,会把 28 缓存在栈中,等到最后执行该 defer 语句的时候取出,即输出 28;

2.defer 缓存的是结构体 Person{28} 的地址,最终 Person{28} 的 age 被重新赋值为 29,所以 defer 语句最后执行的时候,依靠缓存的地址取出的 age 便是 29,即输出 29;

3.闭包引用,输出 29;

又由于 defer 的执行顺序为先进后出,即 3 2 1,所以输出 29 29 28。

21、错吧字符串和nil比较的问题

package main
import (
"fmt"
)
func main() {
var x string = nil // 错误1
if x == nil { // 错误2
x = "default"
}
fmt.Println(x)
}

golang 的字符串类型是不能赋值 nil 的,也不能跟 nil 比较。

22、return后的defer无效问题

var a bool = true
func main() {
defer func(){
fmt.Println("1")
}()
if a == true {
fmt.Println("2")
return
}
defer func(){
fmt.Println("3")
}()
}

输出2 1; defer 关键字后面的函数或者方法想要执行必须先注册,return 之后的 defer 是不能注册的, 也就不能执行后面的函数或方法

23、切片共享底层数组,append扩容后生成新的数组

func main() {

    s1 := []int{1, 2, 3}
s2 := s1[1:]
s2[1] = 4
fmt.Println(s1)
s2 = append(s2, 5, 6, 7)
fmt.Println(s1)
}
[1 2 4]

[1 2 4]

1、golang 中切片底层的数据结构是数组。当使用 s1[1:] 获得切片 s2,和 s1 共享同一个底层数组,这会导致 s2[1] = 4 语句影响 s1。

2、append 操作会导致底层数组扩容,生成新的数组,因此追加数据后的 s2 不会影响 s1。

24、map无序问题

func main() {
m := map[int]string{0:"zero",1:"one"}
for k,v := range m {
fmt.Println(k,v)
}
}
# 由于map无序,所以输出结果为
0 zero
1 one
# 或者
1 one
0 zero

25、defer嵌套其他函数问题

func main() {
a := 1
b := 2
defer calc("1", a, calc("10", a, b))
a = 0
defer calc("2", a, calc("20", a, b))
b = 1
} func calc(index string, a, b int) int {
ret := a + b
fmt.Println(index, a, b, ret)
return ret
}
10 1 2 3
20 0 2 2
2 0 2 2
1 1 3 4

defer会预先把需要的值存起来,如果该值是一个函数的返回,会先计算。之后再按照defer倒序输出

26、指针接收者实现接口,值无法调用问题

type People interface {
Speak(string) string
} type Student struct{} func (stu *Student) Speak(think string) (talk string) {
if think == "speak" {
talk = "speak"
} else {
talk = "hi"
}
return
} func main() {
var peo People = Student{}
think := "speak"
fmt.Println(peo.Speak(think))
}

编译失败;原因是基础面试题26点,注意事项第二点。如果是值接收者,实体类型的值和指针都可以实现对应的接口;如果是指针接收者,那么只有类型的指针能够实现对应的接口

27、接口赋值为nil问题

type People interface {
Show()
} type Student struct{} func (stu *Student) Show() { } func main() { var s *Student
if s == nil {
fmt.Println("s is nil")
} else {
fmt.Println("s is not nil")
}
var p People = s
if p == nil {
fmt.Println("p is nil")
} else {
fmt.Println("p is not nil")
}
}
s is nil

p is not nil

这道题看似有点诧异,我们分配给变量 p 的值明明是 nil,然而 p 却不是 nil。记住一点,当且仅当动态值和动态类型都为 nil 时,接口类型值才为 nil。上面的代码,给变量 p 赋值之后,p 的动态值是 nil,但是动态类型却是 *Student,是一个 nil 指针,所以相等条件不成立

28、go中不同类型不能比较

func main() {
fmt.Println([...]int{1} == [2]int{1})
fmt.Println([]int{1} == []int{1})
}

有两处错误:

1、go 中不同类型是不能比较的,而数组长度是数组类型的一部分,所以 […]int{1} 和 [2]int{1} 是两种不同的类型,不能比较;

2、切片是不能比较的;

29、循环且追加切片

func main() {
v := []int{1, 2, 3}
for i := range v {
v = append(v, i)
}
} fmt.Println(v)
[1 2 3 0 1 2]

不会出现死循环,能正常结束。循环次数在循环开始前就已经确定,循环内改变切片的长度,不影响循环次数。注意,这点跟java不一样

public class Test {

    public static void main(String[] args) {
List<Integer> lss = new ArrayList<>();
lss.add(1);
lss.add(2);
lss.add(3);
for (Integer integer : lss) {
lss.add(integer);
} System.out.println(JSON.toJSON(lss));
}
}
# java的这段循环,会报错
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
at java.util.ArrayList$Itr.next(ArrayList.java:859)
at com.dtstack.common.test.main(test.java:22)

30、协程闭包引用问题

func main() {

    var m = [...]int{1, 2, 3}

    for i, v := range m {
go func() {
fmt.Println(i, v)
}() // 正确写法
// go func(i,v int) {
// fmt.Println(i, v)
// }(i,v)
} time.Sleep(time.Second * 3)
}
2 3
2 3
2 3

各个 goroutine 中输出的 i、v 值都是 for range 循环结束后的 i、v 最终值,而不是各个goroutine启动时的i, v值。可以理解为闭包引用,使用的是上下文环境的值。

31、数组传递给for循环也是值拷贝

func main() {
var a = [5]int{1, 2, 3, 4, 5}
var r [5]int for i, v := range a {
// for i, v := range &a {
if i == 0 {
a[1] = 12
a[2] = 13
}
r[i] = v
}
fmt.Println("r = ", r)
fmt.Println("a = ", a)
}
r =  [1 2 3 4 5]
a = [1 12 13 4 5]

可以对数组的地址进行for循环,或者使用切片都可

func main() {
var a = []int{1, 2, 3, 4, 5}
var r [5]int for i, v := range a {
if i == 0 {
a[1] = 12
a[2] = 13
}
r[i] = v
}
fmt.Println("r = ", r)
fmt.Println("a = ", a)
}
r =  [1 12 13 4 5]
a = [1 12 13 4 5]

32、切片扩容生成新的底层数组

func change(s ...int) {
s = append(s,3)
} func main() {
slice := make([]int,5,5)
slice[0] = 1
slice[1] = 2
// 触发扩容
change(slice...)
fmt.Println(slice)
// 新切片长度为2,容量为5。不会触发扩容,所以会改变底层数组
change(slice[0:2]...)
fmt.Println(slice)
}
[1 2 0 0 0]
[1 2 3 0 0]

Go 提供的语法糖…,可以将 slice 传进可变函数,不会创建新的切片。第一次调用 change() 时,append() 操作使切片底层数组发生了扩容,原 slice 的底层数组不会改变;第二次调用change() 函数时,使用了操作符[i,j]获得一个新的切片,假定为 slice1,它的底层数组和原切片底层数组是重合的,不过 slice1 的长度、容量分别是 2、5,所以在 change() 函数中对 slice1 底层数组的修改会影响到原切片。

33、通道channal和select机制

func main() {
runtime.GOMAXPROCS(1)
int_chan := make(chan int, 1)
string_chan := make(chan string, 1)
int_chan <- 1
string_chan <- "hello"
select {
case value := <-int_chan:
fmt.Println(value)
case value := <-string_chan:
panic(value)
}
}

select 会随机选择一个可用通道做收发操作,所以可能触发异常,也可能不会。

34、常量寻址问题

const i = 100
var j = 123 func main() {
fmt.Println(&j, j)
fmt.Println(&i, i)
}

常量不同于变量的在运行期分配内存,常量通常会被编译器在预处理阶段直接展开,作为指令数据使用,所以常量无法寻址。

35、协程间调度问题

func main() {
ch := make(chan int, 100)
// A
go func() {
for i := 0; i < 10; i++ {
ch <- i
}
}()
// B
go func() {
for {
a, ok := <-ch
if !ok {
fmt.Println("close")
return
}
fmt.Println("a: ", a)
}
}()
close(ch)
fmt.Println("ok")
time.Sleep(time.Second * 10)
}

程序会抛异常。先定义下,第一个协程为 A 协程,第二个协程为 B 协程;当 A 协程还没起时,主协程已经将 channel 关闭了,当 A 协程往关闭的 channel 发送数据时会 panic,panic: send on closed channel。

36、nil的map不能直接赋值,nil的切片可以用append增加元素

func main() {

    var s []int
s = append(s,1) var m map[string]int
m["one"] = 1 // 报错
}

37、常量默认赋值问题

const (
x uint16 = 120
y
s = "abc"
z
)
func main() {
fmt.Printf("%T %v\n", y, y)
fmt.Printf("%T %v\n", z, z)
}
    uint16 120
string abc

38、结构体变量可导出,json反序列化

type People struct {
name string `json:"name"`
}
func main() {
js := `{
"name":"seekload"
}`
var p People
err := json.Unmarshal([]byte(js), &p)
if err != nil {
fmt.Println("err: ", err)
return
}
fmt.Println(p)
}
{}

结构体访问控制,因为 name 首字母是小写,导致其他包不能访问,所以输出为空结构体。

39、结构体虽然值传递,引用字段仍然可操作底层结构

type T struct {
ls []int
}
func foo(t T) {
t.ls[0] = 100
}
func main() {
var t = T{
ls: []int{1, 2, 3},
}
foo(t)
fmt.Println(t.ls[0])
}
100

调用 foo() 函数时虽然是传值,但 foo() 函数中,字段 ls 依旧可以看成是指向底层数组的指针。

40、函数只能和nil比较,不能同其他函数比较

func main() {
var fn1 = func() {}
var fn2 = func() {}
if fn1 != fn2 {
println("fn1 not equal fn2")
}
}
invalid operation: fn1 != fn2 (func can only be compared to nil)

41、recover捕获panic,函数遇panic就不会往下执行

func f() {
defer func() {
if r := recover(); r != nil {
fmt.Printf("recover:%#v", r)
}
}()
panic(1)
panic(2)
} func main() {
f()
}
recover:1

当程序 panic 时就不会往下执行,可以使用 recover() 捕获 panic 的内容。这里panic(2)得不到执行

42、WaitGroup的wait和add和done问题

func main() {
var wg sync.WaitGroup
wg.Add(1)
go func() {
fmt.Println("1")
wg.Done()
wg.Add(1)
}()
wg.Wait()
}

协程里面,使用 再次wg.Add(1) 但是没有其他协程 wg.Done(),导致 panic()。

43、切片共享底层数组及扩容问题

func main() {
a := [3]int{0, 1, 2}
s := a[1:2] // {1} s[0] = 11 // 由于共享底层数组,所以a变为{0, 11, 2} s变为{11}
s = append(s, 12) // a变为{0, 11, 12} s变为{11, 12}
s = append(s, 13) // 超过cap,s发生扩容,不再共享a的底层数组 s变为{11, 12, 13} a仍为{0, 11, 12}
s[0] = 21 // s变为{21, 12, 13} 底层数组不共享a,a仍然为{0, 11, 12} fmt.Println(a)
fmt.Println(s)
}
    [0 11 12]
[21 12 13]

44、切片拷贝问题

func main() {
var src, dst []int
src = []int{1, 2, 3}
copy(dst, src)
fmt.Println(dst)
}
[]

copy(dst, src) 函数返回 len(dst)、len(src) 之间的最小值。如果想要将 src 完全拷贝至 dst,必须给 dst 分配足够的内存空间。

可以预分配空间拷贝,或者使用append函数拷贝

func main() {
var src, dst []int
src = []int{1, 2, 3}
dst = make([]int, len(src))
n := copy(dst, src)
fmt.Println(n,dst)
}
func main() {
var src, dst []int
src = []int{1, 2, 3}
dst = append(dst, src...)
fmt.Println("dst:", dst)
}

45、go的锁不可重入

var mu sync.Mutex
var chain string func main() {
chain = "main"
A()
fmt.Println(chain)
}
func A() {
mu.Lock()
defer mu.Unlock()
chain = chain + " --> A"
B()
} func B() {
chain = chain + " --> B"
C()
} func C() {
mu.Lock()
defer mu.Unlock()
chain = chain + " --> C"
}
fatal error: all goroutines are asleep - deadlock!

会fatal error错误。使用 Lock() 加锁后,不能再继续对其加锁,直到利用 Unlock() 解锁后才能再加锁。

46、结构体带有锁,在赋值的之后会一并赋值当前锁状态

type MyMutex struct {
count int
sync.Mutex
} func main() {
var mu MyMutex
mu.Lock()
var mu1 = mu
mu.count++
mu.Unlock()
mu1.Lock()
mu1.count++
mu1.Unlock()
fmt.Println(mu.count, mu1.count)
}
fatal error: all goroutines are asleep - deadlock!

加锁后复制变量,会将锁的状态也复制,所以 mu1 其实是已经加锁状态,再加锁会死锁。

通过golang小案例,了解golang程序常见机制的更多相关文章

  1. grpc基础讲解和golang实现grpc通信小案例

    grpc简介 gRPC由google开发,是一款语言中立.平台中立.开源的远程过程调用系统 gRPC客户端和服务端可以在多种环境中运行和交互,例如用java写一个服务端,可以用go语言写客户端调用 g ...

  2. 【JavaScript定时器小案例】常见的几种定时器实现的案例

    [JavaScript定时器小案例]常见的几种定时器实现的案例 博客说明 文章所涉及的资料来自互联网整理和个人总结,意在于个人学习和经验汇总,如有什么地方侵权,请联系本人删除,谢谢! 说明 在日常开发 ...

  3. 官方问答--微信小程序常见FAQ (17.8.21-17.8.27)

    给提问的开发者的建议:提问之前先查询 文档.通过社区右上角搜索搜索已经存在的问题. 写一个简明扼要的标题,并且正文描述清楚你的问题. 提交 BUG:需要带上基础库版本号,设备信息(iOS, Andro ...

  4. 小程序-文章:微信小程序常见的UI框架/组件库总结

    ylbtech-小程序-文章:微信小程序常见的UI框架/组件库总结 1.返回顶部 1. 想要开发出一套高质量的小程序,运用框架,组件库是省时省力省心必不可少一部分,随着小程序日渐火爆,各种不同类型的小 ...

  5. Golang - 爬虫案例实践

    目录 Golang - 爬虫案例实践 1. 爬虫步骤 2. 正则表达式 3. 并发爬取美图 Golang - 爬虫案例实践 1. 爬虫步骤 明确目标(确定在哪个网址搜索) 爬(爬下数据) 取(去掉没用 ...

  6. Cookie小案例-----记住浏览过的商品记录

    Cookie小案例------记住浏览过的商品记录 我们知道,这个功能在电商项目中非经常见.这里处理请求和页面显示都是由servlet实现,主要是为了体现cookie的作用, 实现功能例如以下: 1, ...

  7. session的两个小案例

    学完了session,写两个小案例加深一下对session的巩固. 1. 用户登陆案例 登陆html页面提交后,将参数带给处理登陆的servlet,该servlet将获得登陆的用户名和密码,并将这些信 ...

  8. 02SpringMvc_springmvc快速入门小案例(XML版本)

    这篇文章中,我们要写一个入门案例,去整体了解整个SpringMVC. 先给出整个项目的结构图:

  9. SqlDependency缓存数据库表小案例

    SqlDependency的简介: SqlDependency是outputcache网页缓存的一个参数,它的作用是指定缓存失效的数据库依赖项,可以具体到数据库和表. SqlDependency能解决 ...

随机推荐

  1. Codeforces Round #345 (Div. 1) C. Table Compression (并查集)

    Little Petya is now fond of data compression algorithms. He has already studied gz, bz, zip algorith ...

  2. poj3661 Running

    Description The cows are trying to become better athletes, so Bessie is running on a track for exact ...

  3. 哈尔滨理工大学软件与微电子学院程序设计竞赛(同步赛) C.Coronavirus (BFS)

    题意:有一个图,要求从\(S\)走到\(E\),\(.\)表示可以走的路径,\(*\)周围的八个方向均不能走,要求判断是否能走到\(E\),若能,输出最小路径长度,否则输出\(Impossible\) ...

  4. WSL2 Ubuntu apt-get update失败

    情况: 这个问题在github上也有讨论:https://github.com/microsoft/WSL/issues/4342 不过经过我的尝试,是DNS问题,这是默认的配置: 这个配置来自win ...

  5. MySQL 主从复制(上)

    目录 主从复制前提 主从复制原理 涉及的文件 & 线程 Master 主库 Slave 从库 主从复制的搭建 主库配置 配置 /etc/my.cnf 建立专用复制用户 查看 Binlog 信息 ...

  6. Linux-开机运行流程

    目录 CentOS7开机流程 Linux运行级别 systemd进程管理 systemd的优势 systemd相关文件 systemd启动相关命令 systemd开机自启动相关命令 systemd服务 ...

  7. Kubernets二进制安装(14)之flannel之SNAT规则优化

    flannel之SNAT规则优化的目的是由于在K8S中的容器内,访问不同宿主机中的容器的资源的时候,日志文件会记录为宿主机的IP地址,而不是记录为容器本身自己的IP地址,建议在不同的宿主机上的容器互访 ...

  8. leetcode 1 两数之和 hashmap

    主要是hashmap.还有边插入边查找,提高效率和降低空间复杂度. 之前一直用map,结果发现还有hashmap,效率更高. 注意名称空间为 using namespace __gnu_cxx; 问题 ...

  9. Bootstrap巨幕

    这是一个轻量.灵活的组件,它能延伸至整个浏览器视口来展示网站上的关键内容. jumbotron修饰 <div class="jumbotron"> <h1> ...

  10. 【情人节选帽子】TCS34725颜色传感器和Python图形界面编程(STM32 HAL库)

    截图 描述: l  STM32 HAL库编程 l  使用模拟IIC通信,方便程序移植 l  Python界面编写,蘑菇头的帽子是什么颜色 l  STM32 HAL库串口通信 l  Python界面使用 ...