0.遇到一个问题

代码

  1. func GetMap (i interface{})(map[string]interface{}){
  2. if i == nil { //false ???
  3. i = make(map[string]interface)
  4. fmt.Println("xxxxx")
  5. }
  6. }
  7. var testMap map[string]interface{}
  8. getMap := GetMap(testMap)
  9. getMap["add"] = "add" //panic

问题:比较困惑的是对于一个传进来的testMap是nil,但是在GetMap 里面if却是false。实践看来函数内部形参确实已经不是nil。那么interface{}判断nil的具体是什么过程?

找答案: 看了这个视频understanding nil 整理了一下

总结答案

  • 空interface实际数据结构是包含type和value两个字段。
  • 判断interface==nil的时候需要type和value都是null,才等于nil。
  • testMap赋值给i之后,接口包含了赋值对象的类型细信息。的type字段不再是null了,因此代码if的结果就是false。

持续学习

通过遇到的问题引申学习主要解决两个问题

  1. nil到底是什么?
    第一部分标题1-3整理了一些nil在go中的使用,对于不同类型对nil比较的实际操作并举了例子。
  2. interface的存储了什么?
    第二部分标题4对interface实际内存中结构进行了探索。包括带方法的interface和空interface

1.nil是什么

个人理解: 学习之前类比为c的null空指针。学习之后知道有点以偏概全

官方定义:
  1. // nil is a predeclared identifier representing the zero value for a
  2. // pointer, channel, func, interface, map, or slice type.
  3. var nil Type
  4. // Type must be a pointer, channel, func, interface, map, or slice type
  • nil 并不是关键字,只是预定义的标识符。
  • nil代表数据类型的0值,并不仅仅是空指针。
  • nil 可以和 pointer, channel, func, interface, map, or slice 进行比较
不同类型对应的0值如下:
类型 零值
numbers 0
string ""
bool false
pointer nil
slices nil
maps nil
channels nil
functions nil
interfaces nil

结构体的0值
对于结构体来说,每个字段都是nil值,整个结构体才是nil

  1. type Person struct {
  2. Age int
  3. Name string
  4. Friends []Person
  5. }
  6. var p Person // Person{0, "", nil}

2.nil类型

nil 没有类型 不是关键字 可被修改

  1. var nil = errors.New("***")

不同类型对应nil实际判断标准

类型 实际存储 nil判断
pointers 类c 不指向任何内存, 内存安全 垃圾回收
slices [ptr(*elem)\ len()|cap()]
maps,channels,functions ptr 没有初始化
interface (type,data) (nil,nil)
  • 特别的 -- interface 的 nil
    interface 包含type 和 data
    nil interface指的是 type是nil,且 value 是nil
  1. var s fmt.Stringer // Stringer(nil,nil)
  2. fmt.Println(s == nil) //true
  3. //(nil, nil) == nil
  4. var p *Person //nil of type *Person
  5. var s fmt.Stringer = p //Stringer(*Person nil)
  6. fmt.Println(s == nil) // false
  7. //(*Person, nil) != nil
  • nil interface 不等于 nil??

错误例子:这里和最开始的问题类似,函数返回error的时候,定义了一个空的error并返回,在函数碗面判断error!=nil的时候并不是true。所以在实际开发的时候,对于没有error的情况,要直接返回nil。

  1. type error interface {
  2. Error() string
  3. }
  4. func do() error { // 实际 error(*doError, nil)
  5. var err *doError
  6. return err //类型是 *doError 的nil
  7. }
  8. func main(){
  9. err := do() //error (*doError , nil)
  10. fmt.Println(err == nil) //false
  11. }

正确方式:
不定义error类型,直接返回nil

  1. func do() *doError { //nil of type *doError
  2. return nil
  3. }
  4. func main(){
  5. err := do() //nil of type *doError
  6. fmt.Println(err == nil) //true
  7. }

对于多层函数调用
里层函数定义了返回值虽然是nil,但是包含了type类型。所以避免这种写法

  1. func do() *doError{ //nil of type *doError
  2. return nil
  3. }
  4. func wrapDo error { //error(*doError , nil)
  5. return do() //nil of type *doError
  6. }
  7. func main(){
  8. err := wrapDo() //error(*doError,nil)
  9. fmt.Println(err == nil)//false
  10. }

综上:不要声明具体error类型,以为的nil interface实际上已经不是nil了。以上和文章问题的初衷是一致的。因为某种类型的nil赋值给nil interface之后 interface!=nil了。 赋值后的interface虽然没有值,但是已经有类型信息了

nil 不仅仅是 null

3.不同type nil的操作

pointers 取值panic

  1. var p *int
  2. p == nil //true
  3. *p //panic
  4. nil receiver

slices 可遍历 可append 不可取值panic

  1. var s []slice
  2. len(s) // 0
  3. cap(s) // 0
  4. for range s // zero times
  5. s[i] // panic:index out of range
  6. append // ok 自动扩容 1024以内2倍扩容 以上1.25倍

maps 可以遍历 可取值 可赋值

  1. var m map[t]u
  2. len(m) //0
  3. for range m { // zero times
  4. v,ok := m[i] // zero(u), false
  5. m[i] = x
  6. }

channels 读写阻塞 close会panic

  1. //nil channel
  2. var c chan t
  3. <-c //blocks forever
  4. c<-x // blocks forever
  5. close(c) // panic: close of nil channel
  6. //closed channel
  7. v, ok <- c //zero(t),false
  8. c <- x //panic: send on closed channel
  9. close(c) //panic: close of nil channel

interfaces

  1. type Summer interface{
  2. func Sum() int
  3. }
  4. //pointer
  5. var t *tree
  6. var s Summer = t
  7. fmt.Println(t == nil, s.Sum() ) //true, 0
  8. //slice
  9. type ints []int
  10. func (i ints)Sum() int{
  11. s:=0
  12. for _, v := range i {
  13. s += v
  14. }
  15. return s
  16. }
  17. var i ints
  18. var s Summer = i
  19. fmt.Println( i == nil, s.Sum()) //true , 0
  20. // nil value can satisfy nil interface

4.interface

gopher 讲的 interface使用Tomas Senart - Embrace the Interface
Google Understanding Go Interfaces

  • writing generic algorithm
  • hiding implementation detail
  • providing interception points

用于声明方法集合,可嵌套,不包含方法实现。不定义字段。
优势:隐藏一些具体的实现,泛型编程,不用声明实现哪些func运行时确定

4.1 interface数据结构

有方法的接口

iface

iface 是 runtime 中对 interface 进行表示的根类型 (src/runtime/runtime2.go)

  1. type iface struct{
  2. tab *itab //类型信息
  3. data unsafe.Pointer //实际对象指针
  4. }
  5. type itab struct {
  6. inter *interfacetype //接口类型
  7. _type *type //实际对象类型
  8. fun [1]uintptr //实际对象方法地址
  9. ...
  10. }
  • iface 的 itab字段存储接口定义的方法相关信息,method 的具体实现存放在 itab.fun变量里。描述interface类型和其指向的数据类型的数据结构可以看下面gdb调试过程结构的打印.

  • data存储interface持有的具体的值信息,不可被修改。当赋值的a被修改并不会影响interface里面的data

    itab
  • _type 这个类型是 runtime 对任意 Go 语言类型的内部表示。_type 类型描述了一个“类型”的每一个方面: 类型名字,特性(e.g. 大小,对齐方式...),某种程度上类型的行为(e.g. 比较,哈希...) 也包含在内了。。(src/runtime/type.go)

  • interfacetype 的指针,这只是一个包装了 _type 和额外的与 interface 相关的信息的字段。描述了interface本身的类型。(src/runtime/type.go)

  • func 数组持有组成该interface虚表的的函数的指针。

空接口

  • 空接口可以被任何类型赋值,默认值是nil。
  • 没有方法
  • 存储结构也和有方法的interface不同。如下
eface

(src/runtime/runtime2.go)

  1. type eface struct {
  2. _type *_type //对象类型信息
  3. data unsafe.Pointer //对象指针
  4. }
  5. type _type struct {
  6. size uintptr // type size
  7. ptrdata uintptr // size of memory prefix holding all pointers
  8. hash uint32 // hash of type; avoids computation in hash tables
  9. tflag tflag // extra type information flags
  10. align uint8 // alignment of variable with this type
  11. fieldalign uint8 // alignment of struct field with this type
  12. kind uint8 // enumeration for C
  13. alg *typeAlg // algorithm table
  14. gcdata *byte // garbage collection data
  15. str nameOff // string form
  16. ptrToThis typeOff // type for pointer to this type, may be zero
  17. }
  • eface没有方法声明,存储*_type包含类型信息。可以看到一个空接口也存了两个字段,这里根本解释了最开始提到的问题,对于判断interface{}==nil的时候,需要保证接口两个字段都是null才是true。下面4.2debug的例子中调试29行,34行和35行对比ei的时候可以看到,虽然一个nil struct赋值给了interface{}后,空接口的_type,data字段都已经不是null了。
  • interface被赋值之后也支持比较。(如果赋值对象支持比较)
  1. func main(){
  2. var t1,t2 interface{}
  3. fmt.Println(t1==nil) //true
  4. fmt.Println(t1==t2) //true
  5. t1,t2=100,100
  6. fmt.Println(t1==t2) // true
  7. t1,t2=map[string]int{},map[string]int{}
  8. fmt.Println(t1==t2)} //panic runtime error:comparing uncomparable type map[string]int
  9. }

断言 .(asert)

interface{}可作为函数参数,实现泛型编程。
asert 用于判断变量类型 并且 可以判断变量是否实现了某个接口

  1. type data int
  2. func(d data)String()string{
  3. return fmt.Sprintf("data:%d",d)
  4. }
  5. func main(){
  6. var d data=15
  7. var x interface{}=d
  8. if n,ok:=x.(fmt.Stringer);ok{ //转换为更具体的接口类型
  9. fmt.Println(n)
  10. }
  11. if d2,ok:=x.(data);ok{ //转换回原始类型
  12. fmt.Println(d2)
  13. }
  14. e:=x.(error) //错误:main.data is not error
  15. fmt.Println(e)
  16. }
  • 使用ok-idiom模式不用担心转换失败时候panic
  • 利用switch可以在多种类型条件下进行匹配 ps type switch不支持fallthrought
  1. func main(){
  2. var x interface{}=func(x int)string{return fmt.Sprintf("d:%d",x)}
  3. switchv:=x.(type){ //局部变量v是类型转换后的结果
  4. case nil :
  5. fmt.Println("nil")
  6. case*int:
  7. fmt.Println(*v)
  8. case func(int)string:
  9. fmt.Println( v(100) )
  10. case fmt.Stringer:
  11. fmt.Println(v)
  12. default:
  13. fmt.Println("unknown")
  14. }
  15. }
  16. output:100

4.2 debug一下

code

  1. 1 package main
  2. 2 import(
  3. 3 "fmt"
  4. 4 )
  5. 5
  6. 6 type A struct {
  7. 7
  8. 8 }
  9. 9 type Aer interface {
  10. 10 AerGet()
  11. 11 AerSet()
  12. 12 }
  13. 13 func (a A)AerGet(){
  14. 14 fmt.Println("AerGet")
  15. 15 }
  16. 16
  17. 17 func (a *A)AerSet(){
  18. 18 fmt.Println("AerSet")
  19. 19 }
  20. 20 func main(){
  21. 21 var a A
  22. 22 var aer Aer
  23. 23 aer = &a
  24. 24 aer.AerGet()
  25. 25 aer.AerSet()
  26. 26
  27. 27 var ei interface{}
  28. 28 if ei == nil {
  29. 29 fmt.Println("ei is nil")
  30. 30 }else {
  31. 31 fmt.Println("ei not nil")
  32. 32 }
  33. 33 var aa A
  34. 34 ei = aa
  35. 35 if ei == nil {
  36. 36 fmt.Println("ei is nil")
  37. 37 }else {
  38. 38 fmt.Println("ei not nil")
  39. 39 }
  40. 40
  41. 41 }

debug

mac版本10.14.2 gdb版本8.2.1。mac系统更当前新版本之后gdb并不能使用了,尝试创建证书授权给gdb,但是并没有成功。教程gdb wiki
因此使用了lldb。主要打印了eface和iface内存,利用用nil struct对interface{}赋值之后interface{}的内存变化。

  1. * thread #1, stop reason = breakpoint 1.1
  2. frame #0: 0x000000000109376b test`main.main at interfacei.go:23
  3. 20 func main(){
  4. 21 var a A
  5. 22 var aer Aer
  6. -> 23 aer = &a
  7. 24 aer.AerGet()
  8. 25 aer.AerSet()
  9. 26
  10. Target 0: (test) stopped.
  11. (lldb) p aer //interface iface struct
  12. (main.Aer) aer = {
  13. tab = 0x0000000000000000
  14. data = 0x0000000000000000
  15. }
  16. (lldb) n
  17. 21 var a A
  18. 22 var aer Aer
  19. 23 aer = &a
  20. -> 24 aer.AerGet()
  21. 25 aer.AerSet()
  22. 26
  23. 27 var ei interface{}
  24. Target 0: (test) stopped.
  25. (lldb) p aer
  26. (main.Aer) aer = {
  27. tab = 0x000000000112c580
  28. data = 0x000000000115b860
  29. }
  30. (lldb) p &aer
  31. (*main.Aer) = 0x000000000112c580
  32. (lldb) p *aer.tab // itab struct
  33. (runtime.itab) *tab = {
  34. inter = 0x00000000010acc60
  35. _type = 0x00000000010aba80
  36. link = 0x0000000000000000
  37. hash = 474031097
  38. bad = false
  39. inhash = true
  40. unused = ([0] = 0, [1] = 0)
  41. fun = ([0] = 0x0000000001093a10)
  42. }
  43. (lldb) p *aer.tab._type
  44. (runtime._type) *_type = {
  45. size = 0x0000000000000008
  46. ptrdata = 0x0000000000000008
  47. hash = 474031097
  48. tflag = 1
  49. align = 8
  50. fieldalign = 8
  51. kind = 54
  52. alg = 0x000000000113bd50
  53. gcdata = 0x00000000010d4ae4
  54. str = 6450
  55. ptrToThis = 0
  56. }
  57. (lldb) p *aer.tab.inter //inter struct
  58. (runtime.interfacetype) *inter = {
  59. typ = {
  60. size = 0x0000000000000010
  61. ptrdata = 0x0000000000000010
  62. hash = 2400961726
  63. tflag = 7
  64. align = 8
  65. fieldalign = 8
  66. kind = 20
  67. alg = 0x000000000113bd80
  68. gcdata = 0x00000000010d4ae6
  69. str = 10139
  70. ptrToThis = 45184
  71. }
  72. pkgpath = {
  73. bytes = 0x0000000001093e78
  74. }
  75. mhdr = (len 2, cap 2) {
  76. [0] = (name = 5032, ityp = 61664)
  77. [1] = (name = 5041, ityp = 61664)
  78. }
  79. }
  80. (lldb) n
  81. ei is nil
  82. 27 var ei interface{}
  83. 28 if ei == nil {
  84. 29 fmt.Println("ei is nil")
  85. 30 }else {
  86. 31 fmt.Println("ei not nil")
  87. 32 }
  88. 33 var aa A //aa == nil
  89. -> 34 ei = aa
  90. 35 if ei == nil {
  91. 36 fmt.Println("ei is nil")
  92. 37 }else {
  93. Target 0: (test) stopped.
  94. (lldb) p ei //interface{} == ni
  95. (interface {}) ei = { //eface struct
  96. _type = 0x0000000000000000
  97. data = 0x0000000000000000
  98. }
  99. (lldb) n
  100. 32 }
  101. 33 var aa A
  102. 34 ei = aa
  103. -> 35 if ei == nil {
  104. 36 fmt.Println("ei is nil")
  105. 37 }else {
  106. 38 fmt.Println("ei not nil")
  107. (lldb) p ei
  108. (interface {}) ei = { //interface{} != nil
  109. _type = 0x00000000010acbe0
  110. data = 0x000000000115b860
  111. }
  112. (lldb) p *ei._type // _type struct
  113. (runtime._type) *_type = {
  114. size = 0x0000000000000000
  115. ptrdata = 0x0000000000000000
  116. hash = 875453117
  117. tflag = 7
  118. align = 1
  119. fieldalign = 1
  120. kind = 153
  121. alg = 0x000000000113bd10
  122. gcdata = 0x00000000010d4ae4
  123. str = 6450
  124. ptrToThis = 98304
  125. }

汇编

汇编代码看不大懂,放在这里督促学习。

  1. go build -gcflags '-l' -o interfacei interfacei.go
  2. go tool objdump -s "main\.main" interfacei
  3. TEXT main.main(SB) /Users/didi/go/src/test/interface/interfacei.go
  4. interfacei.go:20 0x10936b0 65488b0c25a0080000 MOVQ GS:0x8a0, CX
  5. interfacei.go:20 0x10936b9 483b6110 CMPQ 0x10(CX), SP
  6. interfacei.go:20 0x10936bd 0f8635010000 JBE 0x10937f8
  7. interfacei.go:20 0x10936c3 4883ec70 SUBQ $0x70, SP
  8. interfacei.go:20 0x10936c7 48896c2468 MOVQ BP, 0x68(SP)
  9. interfacei.go:20 0x10936cc 488d6c2468 LEAQ 0x68(SP), BP
  10. interfacei.go:20 0x10936d1 488d05e8920100 LEAQ 0x192e8(IP), AX
  11. interfacei.go:21 0x10936d8 48890424 MOVQ AX, 0(SP)
  12. interfacei.go:21 0x10936dc e8afb7f7ff CALL runtime.newobject(SB)
  13. interfacei.go:21 0x10936e1 488b442408 MOVQ 0x8(SP), AX
  14. interfacei.go:21 0x10936e6 4889442430 MOVQ AX, 0x30(SP)
  15. //24 aer.AerGet()
  16. interfacei.go:24 0x10936eb 48890424 MOVQ AX, 0(SP)
  17. interfacei.go:24 0x10936ef e87c010000 CALL main.(*A).AerGet(SB)
  18. interfacei.go:24 0x10936f4 488b442430 MOVQ 0x30(SP), AX
  19. //25 aer.AerSet()
  20. interfacei.go:25 0x10936f9 48890424 MOVQ AX, 0(SP)
  21. interfacei.go:25 0x10936fd e82effffff CALL main.(*A).AerSet(SB)
  22. interfacei.go:29 0x1093702 48c744244800000000 MOVQ $0x0, 0x48(SP)
  23. interfacei.go:29 0x109370b 48c744245000000000 MOVQ $0x0, 0x50(SP)
  24. interfacei.go:29 0x1093714 488d0505030100 LEAQ 0x10305(IP), AX
  25. interfacei.go:29 0x109371b 4889442448 MOVQ AX, 0x48(SP)
  26. interfacei.go:29 0x1093720 488d0dd9240400 LEAQ 0x424d9(IP), CX
  27. interfacei.go:29 0x1093727 48894c2450 MOVQ CX, 0x50(SP)
  28. interfacei.go:29 0x109372c 488d4c2448 LEAQ 0x48(SP), CX
  29. interfacei.go:29 0x1093731 48890c24 MOVQ CX, 0(SP)
  30. interfacei.go:29 0x1093735 48c744240801000000 MOVQ $0x1, 0x8(SP)
  31. interfacei.go:29 0x109373e 48c744241001000000 MOVQ $0x1, 0x10(SP)
  32. interfacei.go:29 0x1093747 e8b48dffff CALL fmt.Println(SB)
  33. interfacei.go:29 0x109374c 488d056d920100 LEAQ 0x1926d(IP), AX
  34. // 35 if ei == nil {
  35. interfacei.go:35 0x1093753 4885c0 TESTQ AX, AX
  36. interfacei.go:35 0x1093756 7454 JE 0x10937ac
  37. //38 fmt.Println("ei not nil")
  38. interfacei.go:38 0x1093758 48c744245800000000 MOVQ $0x0, 0x58(SP)
  39. interfacei.go:38 0x1093761 48c744246000000000 MOVQ $0x0, 0x60(SP)
  40. interfacei.go:38 0x109376a 488d05af020100 LEAQ 0x102af(IP), AX
  41. interfacei.go:38 0x1093771 4889442458 MOVQ AX, 0x58(SP)
  42. interfacei.go:38 0x1093776 488d05a3240400 LEAQ 0x424a3(IP), AX
  43. interfacei.go:38 0x109377d 4889442460 MOVQ AX, 0x60(SP)
  44. interfacei.go:38 0x1093782 488d442458 LEAQ 0x58(SP), AX
  45. interfacei.go:38 0x1093787 48890424 MOVQ AX, 0(SP)
  46. interfacei.go:38 0x109378b 48c744240801000000 MOVQ $0x1, 0x8(SP)
  47. interfacei.go:38 0x1093794 48c744241001000000 MOVQ $0x1, 0x10(SP)
  48. interfacei.go:38 0x109379d e85e8dffff CALL fmt.Println(SB)
  49. interfacei.go:41 0x10937a2 488b6c2468 MOVQ 0x68(SP), BP
  50. interfacei.go:41 0x10937a7 4883c470 ADDQ $0x70, SP
  51. interfacei.go:41 0x10937ab c3 RET
  52. interfacei.go:36 0x10937ac 48c744243800000000 MOVQ $0x0, 0x38(SP)
  53. interfacei.go:36 0x10937b5 48c744244000000000 MOVQ $0x0, 0x40(SP)
  54. interfacei.go:36 0x10937be 488d055b020100 LEAQ 0x1025b(IP), AX
  55. interfacei.go:36 0x10937c5 4889442438 MOVQ AX, 0x38(SP)
  56. interfacei.go:36 0x10937ca 488d053f240400 LEAQ 0x4243f(IP), AX
  57. interfacei.go:36 0x10937d1 4889442440 MOVQ AX, 0x40(SP)
  58. interfacei.go:36 0x10937d6 488d442438 LEAQ 0x38(SP), AX
  59. interfacei.go:36 0x10937db 48890424 MOVQ AX, 0(SP)
  60. interfacei.go:36 0x10937df 48c744240801000000 MOVQ $0x1, 0x8(SP)
  61. interfacei.go:36 0x10937e8 48c744241001000000 MOVQ $0x1, 0x10(SP)
  62. interfacei.go:36 0x10937f1 e80a8dffff CALL fmt.Println(SB)
  63. interfacei.go:35 0x10937f6 ebaa JMP 0x10937a2
  64. interfacei.go:20 0x10937f8 e883aafbff CALL runtime.morestack_noctxt(SB)
  65. interfacei.go:20 0x10937fd e9aefeffff JMP main.main(SB)

参考

Go Interface 源码剖析
Tomas Senart - Embrace the Interface
Google Understanding Go Interfaces
understanding nil

goalng nil interface浅析的更多相关文章

  1. Go语言第一深坑:interface 与 nil 的比较

    interface简介 Go 语言以简单易上手而著称,它的语法非常简单,熟悉 C++,Java 的开发者只需要很短的时间就可以掌握 Go 语言的基本用法. interface 是 Go 语言里所提供的 ...

  2. 【荐】详解 golang 中的 interface 和 nil

    golang 的 nil 在概念上和其它语言的 null.None.nil.NULL一样,都指代零值或空值.nil 是预先说明的标识符,也即通常意义上的关键字.在 golang 中,nil 只能赋值给 ...

  3. SQLite浅析

    对于iOS工程师有一道常考的面试题,即iOS数据存储的方式 标答如下: Plist(NSArray\NSDictionary) Preference (偏好设置\NSUserDefaults) NSC ...

  4. 理解Go Interface

    理解Go Interface 1 概述 Go语言中的接口很特别,而且提供了难以置信的一系列灵活性和抽象性.接口是一个自定义类型,它是一组方法的集合,要有方法为接口类型就被认为是该接口.从定义上来看,接 ...

  5. Go“一个包含nil指针的接口不是nil接口”踩坑

    最近在项目中踩了一个深坑--"Golang中一个包含nil指针的接口不是nil接口",总结下分享出来,如果你不是很理解这句话,那推荐认真看下下面的示例代码,避免以后写代码时踩坑. ...

  6. 重学Golang系列(一): 深入理解 interface和reflect

    前言 interface(即接口),是Go语言中一个重要的概念和知识点,而功能强大的reflect正是基于interface.本文即是对Go语言中的interface和reflect基础概念和用法的一 ...

  7. 如何理解golang中的nil

    nil的奇怪行为 刚接触golang时,发现nil在不同的上下文,行为表现是不同的,并且和其他语言中的表现,也不大相同 实例1:输入true, true, false,不符合传递性 func main ...

  8. Golang | 既是接口又是类型,interface是什么神仙用法?

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是golang专题的第12篇文章,我们来继续聊聊interface的使用. 在上一篇文章当中我们介绍了面向对象的一些基本概念,以及gol ...

  9. UI数据库

    一.数据库 SQL: SQL是Structured Query Language(结构化查询语言)的缩写.SQL是专为数据库而建立的操作命令集, 是一种功能齐全的数据库语言. 二.数据库管理系统 数据 ...

随机推荐

  1. zookeeper应用 - 配置服务

    一端不停的更新配置,另一端监听这个配置的变化.     需要注意的是:监听端不一定读取到所有的变化.在zk服务器发送通知到客户端,客户端读取数据注册监听之间可能发生了多次数据变化,这些数据变化是得不到 ...

  2. C#秒转换小时

    #region 秒转换小时 SecondToHour /// <summary> /// 秒转换小时 /// </summary> /// <param name=&qu ...

  3. 事件驱动模型 IO多路复用 阻塞IO与非阻塞IO select epool

    一.事件驱动 1.要理解事件驱动和程序,就需要与非事件驱动的程序进行比较.实际上,现代的程序大多是事件驱动的,比如多线程的程序,肯定是事件驱动的.早期则存在许多非事件驱动的程序,这样的程序,在需要等待 ...

  4. Android UI组件----自定义ListView实现动态刷新

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/3 ...

  5. 304 Not Modified 简述

    在客户端向服务端发送http请求时,若返回状态码为304 Not Modified 则表明此次请求为条件请求.在请求头中有两个请求参数:If-Modified-Since 和 If-None-Matc ...

  6. asar 如何解密加密?electron 的 asar 的具体用法

    来源:https://newsn.net/say/electron-asar.html 在electron中,asar是个特殊的代码格式.asar包里面包含了程序猿编写的代码逻辑.默认情况下,这些代码 ...

  7. Beanstalkd 的理解

    Beanstalkd 的理解 Beanstalkd 是一个轻量级的内存型队列,利用了和Memcache 类似的协议.其官网beanstakkd官网 下方的感谢语说: Many thanks to me ...

  8. tomcat-7.0.30安装及配置

    使用说明: 一.1.下载jdk(http://java.sun.com/javase/downloads/index.jsp),2.安装jdk-6u14-windows-i586.exe 3.配置环境 ...

  9. 我的Java之旅——之后的学习计划

      在写完第一个Java程序之后,对于一些最最基本的东西有了大致的了解,对于之后的学习,我做了简单的计划. 7月17号:补充一些基本内容. 7月18.19号: 1. Java的一些常用类,包括 :Nu ...

  10. Spring 利用PropertyPlaceholderConfigurer占位符

      Hey Girl   博客园    首页    博问    闪存    新随笔    订阅     管理 posts - 42,  comments - 3,  trackbacks - 0 Sp ...