go int 转切片_一文掌握GO语言实战技能(二)

  • Go 数组
  • Go 切片
  • Go 变量和内存地址
  • Go Map 类型
  • Go 面向对象编程
  • Go 方法的定义

GO 数组

数组是同一类型的元素集合。Go中的数组下标从0开始,因此长度为n的数组下标范围是[0, n-1]。

整数数组中元素默认初始化为0,字符串数组中的元素默认初始化为""。

 var a [3]int
 a[0] = 10
 a[1] = 20
 
var a [3]int = [3]int{10, 20, 30}
//定义时数组初始化

//数组初始化
 var a [3]int = [3]int{10, 20, 30}
//定义时数组初始化

a := [3]int{10, 20, 30}
//定义时数组初始化

a := [...]int{10, 20, 30}
//定义时数组初始化
 
a := [3]int{10}
//定义时数组初始化

a := [3]int{2:10}
//定义时数组初始化
  • 数组⻓度是类型的⼀部分
var a [3]int
a[0] = 10
a[1] = 20
a[2] = 30
var b [5]int
b=a
//a、b是不同类型的数组,不能赋值
  • len 内置函数
var a [3]int
a[0] = 10
a[1] = 20
a[2] = 30

fmt.Printf(“len:%d\n”, len(a))
  • 数组的遍历

a. 下标进行遍历

b. range 函数进行遍历

range函数是个神奇而有趣的内置函数,你可以使用它来遍历数组,切片和字典。

  • 当用于遍历数组和切片的时候,range函数返回索引和元素。

  • 当用于遍历字典的时候,range函数返回字典的键和值。

package main

import "fmt"

func main() {
    var a [3]int
    a[0] = 10
    a[1] = 20
    a[2] = 30
    // 使用下标遍历
    for i := 0; i       // fmt.Printf(a[i] + " ")
    }
 
    for index, val := range a {
      // fmt.Printf(a[i] + " ")
    }
    // 这里我们使用range来计算一个切片的所有元素和
    // 这种方法对数组也适用
    nums := []int{2, 3, 4}
    sum := 0
    for _, num := range nums {
        sum += num
    }
    fmt.Println("sum:", sum)

    // range 用来遍历数组和切片的时候返回索引和元素值
    // 如果我们不要关心索引可以使用一个下划线(_)来忽略这个返回值
    // 当然我们有的时候也需要这个索引
    for i, num := range nums {
        if num == 3 {
            fmt.Println("index:", i)
        }
    }

    // 使用range来遍历字典的时候,返回键值对。
    kvs := map[string]string{"a": "apple", "b": "banana"}
    for k, v := range kvs {
        fmt.Printf("%s -> %s\n", k, v)
    }

    // range函数用来遍历字符串时,返回Unicode代码点。
    // 第一个返回值是每个字符的起始字节的索引,第二个是字符代码点,
    // 因为Go的字符串是由字节组成的,多个字节组成一个rune类型字符。
    for i, c := range "go" {
        fmt.Println(i, c)
    }
}
sum: 9
index: 1
a -> apple
b -> banana
0 103
1 111
  • Go数组排序

Go 分别提供了sort.Float64s()  sort.Strings()  sort.Ints() 对不同类型的数组进行排序,默认是升序。

降序需要使用sort.Reverse。

package mainimport ("fmt""sort"
)
func main() {
 
   arrayInt := []int{3, 1, 2, 5, 4}
 
   arrayFloat := []float64{3.2, 1.8, 1.9, 2.2, 4.3}
 
   arrayString := []string{"abc", "ab", "bc"}
 
   // 升序
    sort.Ints(arrayInt)
    sort.Float64s(arrayFloat)
    sort.Strings(arrayString)

    fmt.Println("sort int:", arrayInt)
    fmt.Println("sort float:", arrayFloat)
    fmt.Println("sort ", arrayString)

    // 降序
    sort.Sort(sort.Reverse(sort.IntSlice(arrayInt)))
    sort.Sort(sort.Reverse(sort.Float64Slice(arrayFloat)))
    sort.Sort(sort.Reverse(sort.StringSlice(arrayString)))

    fmt.Println("After reversed: ")

    fmt.Println("sort int:", arrayInt)
    fmt.Println("sort float:", arrayFloat)
    fmt.Println("sort ", arrayString)
 
}
  • 数组的拷贝和传参

a. 数组是值类型

var a [3]int
a[0] = 10
a[1] = 20
a[2] = 30
b := a
//b拷⻉了数组a中所有元素
b[0] = 1000
a: [10,20,30]
b: [1000,20,30]

b. 数组是值类型,函数传参也会拷⻉

package mainimport ("fmt")
func main() {
  var a [3]int
  a[0] = 10
  a[1] = 20
  a[2] = 30
  
  modify(a) 
  fmt.Println(a)    // [10,20,30]
}
func modify(b [3]int) {
  b[0] = 1000
  fmt.Println(b)    // [1000,20,30]
  return
}

GO 切片

GO的切片是基于数组类型的一层封装。Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。

 var a []int
//定义⼀个int类型的空切⽚
  • 切⽚初始化, a[start:end]创建⼀个包括从start到end-1的切⽚。
package mainimport ("fmt"
)
func main() {
    // 初始化方法1
    a:= [5]int{76, 77, 78, 79, 80}
    var b []int = a[1: 4] //基于数组a
    // 创建⼀个切⽚,包括元素a[1] a[2] a[3]
    fmt.Println(b)
    
    // 初始化方法2
    c:=[]int{6, 7, 8} //创建一个数组并返回⼀个切⽚
    fmt.Println(c)
}

  • 数组切片的基本操作

a. arr[start:end]:包括start到end-1(包括end-1)之间的所有元素

b. arr[start:]:包括start到arr最后⼀个元素(包括最后一个元素)之间的所有元素

c. arr[:end]:包括0到end-1(包括end-1)之间的所有元素

d. arr[:]:包括整个数组的所有元素

  • 切⽚修改
package mainimport ("fmt"
)
func main() {
    
    //创建⼀个数组,其中[...]是编译器确定数组的长度,darr的长度是9
   darr:=[...]int{57, 89, 90, 82, 100, 78, 67, 69, 59}
   //基于darr创建⼀个切⽚dslice,包括darr[2],darr[3],darr[4]三个元素
   dslice:=darr[2:5]
   fmt.Println("array before",darr)
   for i:=range dslice {
     //对于dslice中每个元素进行+1,其实修改是darr[2],darr[3],darr[4]
    dslice[i]++
  }
 
  fmt.Println("array after",darr)
}      
// array before [57 89 90 82 100 78 67 69 59]
// array after [57 89 91 83 101 78 67 69 59]

切片是数组的引用,当两个切片源于一个数组,改变其中一个数组,另一个数组也响应的进行的修改。

package mainimport ("fmt"
)
func main() {
    
 numa:=[3]int{78, 79 ,80}
 //创建⼀个切⽚,包含整个数组的所有元素
  
 nums1 := numa[:]
 nums2 := numa[:]

 fmt.Println("array before change 1",numa)
   
 nums1[0]= 100
  
 fmt.Println("array after modification to slice nums1", numa)
   
 nums2[1]=101
  
 fmt.Println("array after modification to slice nums2", numa)

// array before change 1 [78 79 80]
// array after modification to slice nums1 [100 79 80]
// array after modification to slice nums2 [100 101 80]
  • 使⽤make创建切片

make为内建类型slice、map和channel分配内存。

 package mainimport ("fmt"
  )
 func main() {
    //[]中没有⻓度 第一个5 是切片的长度,第二个 5是切片的容量
    i:=make([]int, 5, 5)
    fmt.Println(i)
 }
 // [0 0 0 0 0]
  • 切片的⻓度和容量
 package mainimport ("fmt"
  )
 func main() {
 
    var a []int

    a =make([]int, 5, 10)
    a[0] = 10
    fmt.Printf("a=%v addr:%p len:%d cap:%d\n", a,a,len(a),cap(a))   // a=[10 0 0 0 0] addr:0xc0000a0000 len:5 cap:10

    a= append(a,11)
    fmt.Printf("a=%v addr:%p len:%d cap:%d\n", a,a,len(a),cap(a))  //a=[10 0 0 0 0 11] addr:0xc00009e000 len:6 cap:10

    for i:=0; i 8;i++ {
      a= append(a, i)
      fmt.Printf("a=%v addr:%p len:%d cap:%d\n", a,a,len(a),cap(a))
      // a=[10 0 0 0 0 11 0] addr:0xc00009e000 len:7 cap:10
      // a=[10 0 0 0 0 11 0 1] addr:0xc00009e000 len:8 cap:10
      // a=[10 0 0 0 0 11 0 1 2] addr:0xc00009e000 len:9 cap:10
      // a=[10 0 0 0 0 11 0 1 2 3] addr:0xc00009e000 len:10 cap:10
      // a=[10 0 0 0 0 11 0 1 2 3 4] addr:0xc0000a4000 len:11 cap:20
      // a=[10 0 0 0 0 11 0 1 2 3 4 5] addr:0xc0000a4000 len:12 cap:20
      // a=[10 0 0 0 0 11 0 1 2 3 4 5 6] addr:0xc0000a4000 len:13 cap:20
      // a=[10 0 0 0 0 11 0 1 2 3 4 5 6 7] addr:0xc0000a4000 len:14 cap:20
    }
    // 观察切片的扩容操作 扩容的策略是翻倍扩容
    a = append(a,1000)
    fmt.Printf("a=%v addr:%p len:%d cap:%d\n", a,a,len(a),cap(a))
    // a=[10 0 0 0 0 11 0 1 2 3 4 5 6 7 1000] addr:0xc0000200a0 len:15 cap:20
 }

例子2:

package mainimport ("fmt"
)
func main() {
     
  fruitarray :=[...]string{
   
    "apple", "orange", "grape",
      
    "mango", "water melon",
    
    "pine apple", "chikoo"}
    
  fruitslice:=fruitarray[1:3]//长度是2,容量is 6
     
  fmt.Printf("length of slice %d capacity %d",len(fruitslice), cap(fruitslice))
}  
// length of slice 2 capacity 6
  • 切片再切片
package mainimport ("fmt"
)
func main() {
     
  fruitarray:=[...]string{
    
    "apple", "orange", "grape", "mango",
        
    "water melon", "pine apple", "chikoo"}
      
    fruitslice:=fruitarray[1:3]
    //长度是2, 容量是6
     
    fmt.Printf("length of slice %d capacity %d\n",len(fruitslice), cap(fruitslice))
    //再重新进行切⽚,不能⼤于数组fruitarray的⻓度,否则越界
    
    fruitslice = fruitslice[:cap(fruitslice)]
        
    fmt.Println("After re-slicing length is",len(fruitslice), "and capacity is",cap(fruitslice))
           
}

// length of slice 2 capacity 6
// After re-slicing length is 6 and capacity is 6
  • append 操作
package mainimport ("fmt"
)
func main() {
 cars:=[]string{"Ferrari", "Honda", "Ford"}
  //⻓度和容量都等于3
  fmt.Println("cars:", cars, "has old length",len(cars), "and capacity", cap(cars))
          
  cars=append(cars, "Toyota")
  //容量等于6
   
  fmt.Println("cars:", cars, "has new length",len(cars), "and capacity", cap(cars))
}
// cars: [Ferrari Honda Ford] has old length 3 and capacity 3
// cars: [Ferrari Honda Ford Toyota] has new length 4 and capacity 6

a. append⼀个切⽚

package mainimport ("fmt"
)
func main() {
    
  veggies:=[]string{"potatoes","tomatoes","brinjal"}
          
  fruits :=[]string{"oranges","apples"}
  //fruits后⾯的3个点表示展开fruits切⽚成⼀个元素
      
  food:= append( veggies, fruits...)
  fmt.Println("food:",food)
}
//  food: [potatoes tomatoes brinjal oranges apples]
  • 空切片
package mainimport ("fmt"
  )
  func main() {
    //定义names是⼀个空切⽚,⻓度和容量都等于0
    //不能对空切⽚进行访问,否则panic
   
 var names []string
    
 if names == nil {
     
     fmt.Println("slice is nil going to append")
      
     names = append(names, "John", "Sebastian", "Vinay")
            
     fmt.Println("names contents:",names)   
 }
}
  • 切片传参
package mainimport ("fmt"
)//在函数内部修改numbers切⽚的值
func subtactOne(numbers []int) {
    for i:= range numbers {
      numbers[i]-=2
    }
}
func main() {
    nos:=[]int{8, 7, 6}
    fmt.Println("slice before function call", nos)
    subtactOne(nos)
    //nos修改⽣效了,说明切片是引⽤类型
    fmt.Println("slice after function call", nos)
}
// slice before function call [8 7 6]
// slice after function call [6 5 4]
  • 切片深拷贝
package mainimport ("fmt"
)
func main() {
   // 当元素数量超过容量
   // 切片会在底层申请新的数组
   slice := make([]int, 5, 5)
   slice1 := slice
   slice = append(slice, 1)
   slice[0] = 1
   fmt.Println(slice)//[1 0 0 0 0 1]
   fmt.Println(slice1)//[0 0 0 0 0]
   // copy 函数提供深拷贝功能
   // 但需要在拷贝前申请空间
   slice2 := make([]int, 4, 4)
   slice3 := make([]int, 5, 5)
   fmt.Println(copy(slice2, slice))//4
   fmt.Println(copy(slice3, slice))//5
   fmt.Println(slice2)// [1 0 0 0]
   fmt.Println(slice3)// [1 0 0 0 0]
   slice2[1] = 2
   slice3[1] = 3
   fmt.Println(slice)//[1 0 0 0 0 1]
   fmt.Println(slice2)//[1 2 0 0]
   fmt.Println(slice3)//[1 3 0 0 0]
}
  • 切片遍历
var a [3]int
a[0] = 10
a[1] = 20
a[2] = 30
B := a[:]
for index, val := range b {

}
//和数组遍历是⼀样的
  • new⽤于各种类型的内存分配,new返回是⼀个指针

Go 变量和内存地址

每个变量都有内存地址,可以说通过变量来操作对应⼤大⼩小的内存 。注意:通过&符号可以获取变量的地址。

普通变量存储的是对应类型的值,这些类型就叫值类型 例: var a int32。

指针类型的变量存储的是一个地址,所以⼜叫指针类型或引用类型, 在定义时,前方加*就变为引用类型,var a *int32, a中存储的是一个地址,我们称为引用类型或者指针类型。

package mainimport ("fmt"
)
func main() {
  var a int32
  a = 100
  fmt.Printf("%d\n", a)
  fmt.Printf("%p\n", &a)
  b:=255
     
  var c *int = &b
       
  fmt.Printf("Type of c is %T\n", c)
          
  fmt.Println("address of b is", c)
}
// 100
// 0xc00001608c
// Type of a is *int
// address of b is 0xc00009a008
cf35d14a2b009b1eed6939b0ee80758e.png
  • 指针类型变量的默认值为nil,也就是空地址
package mainimport ("fmt"
)
func main() {
  a := 25 
  var b *int 
  if b == nil {
    fmt.Println("b is", b) 
    b = &a
    fmt.Println("b after initialization is", b)
  }
}
// b is 
// b after initialization is 0xc0000a2008
  • 如果操作指针变量指向的地址里面的值呢?

注意:通过* 符号可以获取指针变量指向的变量。

package mainimport ("fmt"
)
func main() {
  b := 255
  a := &b
    
  fmt.Println("address of b is", a)
        
  fmt.Println("value of b is",*a)
}
// address of b is 0xc00009a008
// value of b is 255
  • 通过指针修改变量的值
package mainimport ("fmt"
)
func main() {
  b := 255
  a := &b
    
  fmt.Println("address of b is", a)
  fmt.Println("value of b is", *a)
  *a++
  fmt.Println("new value of b is",b)
}
// address of b is 0xc00009a008
// value of b is 255
// new value of b is 256
  • 指针变量传参
package mainimport ("fmt"

func change (val *int){
  *val = 55
}
func main() {
  a := 255
  fmt.Println("value of a before function call is",a)
  b := &a
  change(b)
  fmt.Println("value of a after function call is", a)
}
// value of a before function call is 255
// value of a after function call is 55

// 例子2
func change (arr *[3]int){
  (*arr)[0] = 90
}
func main() {
  a:=[3]int{89, 90, 91}
  change(&a)
  fmt.Println(a)
}
// [90 90 91]

对比 切片传参注意:切片是引用类型!!
func change (arr []int){
  arr[0] = 90
}
func main() {
  a:=[3]int{89, 90, 91}
  change(a[:])
  fmt.Println(a)
}
// [90 90 91]
// make⽤来分配引⽤类型的内存,⽐如 map、slice以及channel ,new⽤来分配除引用类型的所有其他类型的内存,⽐如 int、数组等
 
  • 值拷⻉和引⽤拷⻉
 package mainimport ("fmt"
 )
 func main() {
     // 值拷贝
     var a int = 100
     b := a
     
    // 引用拷贝
     var a int = 100
     var b *int = &a
     var c *int = b
     *c = 200
 }
c659175e70768895a77a82eead2c0a88.png

Go Map 类型

map类型是⼀个key-value的数据结构。注意:map必须初始化才能使⽤,否则panic。

map类型的变量默认初始化为nil,需要使用make分配map内存。

//var a map[key的类型]value类型
     
var a map[string]int
var b map[int]string
var c map[float32]string
package mainimport ("fmt"

func main() {  
  var a map[string]int
  if a == nil {
    fmt.Println("map is nil. Going to make one.")
    a = make(map[string]int)  
  }
}

  • map插入操作
package mainimport ("fmt"

func main() {  
  a := make(map[string]int)
  a["steve"] = 12000
  a["jamie"] = 15000
  a["mike"] = 9000
  fmt.Println("a map contents:", a)
}
// a map contents: map[jamie:15000 mike:9000 steve:12000]
  • map 声明方式二, 通过key访问map中的元素
package mainimport ("fmt"

func main() {  
  a := map[string]int {
    "steve": 12000,
    "jamie": 15000,
  }
  a["mike"] = 9000
  fmt.Println("a map contents:", a)
}
  • 如何判断map指定的key是否存在? value, ok := map[key]
package mainimport ("fmt"

func main() {  
  a := map[string]int {
    "steve": 12000,
    "jamie": 15000,
  }
  a["mike"] = 9000
  b := "joe"
  value, ok := a[b]
  if ok == true {
    fmt.Println("Salary of", b, "is", value)
  } else {
    fmt.Println(b,"not found")
  }
  fmt.Println("a map contents:", a)
}
// joe not found
// a map contents: map[jamie:15000 mike:9000 steve:12000]
  • map遍历操作
package mainimport ("fmt"

func main() {  
  a := map[string]int {
    "steve": 12000,
    "jamie": 15000,
  }
  a["mike"] = 9000
  for key, value:= range a {
      fmt.Printf("personSalary[%s] = %d\n", key, value)
  }
}
// personSalary[steve] = 12000
// personSalary[jamie] = 15000
// personSalary[mike] = 9000
  • map删除元素
package mainimport ("fmt"

func main() {  
  a := map[string]int {
    "steve": 12000,
    "jamie": 15000,
  }
  a["mike"] = 9000
  delete(a, "steve")
  fmt.Println("map after deletion", a)
}
// map after deletion map[jamie:15000 mike:9000]
  • map的⻓度  len(a)
package mainimport ("fmt"

func main() {  
  a := map[string]int {
    "steve": 12000,
    "jamie": 15000,
  }
  a["mike"] = 9000
  fmt.Println("length is", len(a))
}
// length is 3
  • map是引⽤类型
package mainimport ("fmt"

func main() {  
  a := map[string]int {
    "steve": 12000,
    "jamie": 15000,
  }
  a["mike"] = 9000
  b := a
  b["mike"] = 18000
  fmt.Println("a map changed", a)
}
// a map changed map[jamie:15000 mike:18000 steve:12000]
  • 默认情况下,map并不是按照key有序进⾏遍历的 ,map按照key进行排序,遍历 。
package mainimport ("fmt""sort"
)
func main() {
   var a map[string]int = make(map[string]int, 10)
   for i := 0; i 10; i++ {
     key := fmt.Sprintf("key%d", i)
     a[key] = i
   }
   var keys []string
   for key, _ := range a {
     keys = append(keys, key)
   }
   sort.Strings(keys)
   for _, key := range keys {
     fmt.Printf("key:%s=%d\n", key, a[key])
   }
}
 
// key:key0=0
// key:key1=1
// key:key2=2
// key:key3=3
// key:key4=4
// key:key5=5
// key:key6=6
// key:key7=7
// key:key8=8
// key:key9=9
  • map类型的切⽚
  package mainimport ("fmt"
  )
  func main() {
    var mapSlice []map[string]int
    mapSlice = make([]map[string]int, 5)
    fmt.Println("before map init")
    for index, value := range mapSlice {
        fmt.Printf("index:%d value:%v\n", index, value)
    }
  

    mapSlice[0] = make(map[string]int, 10)
    mapSlice[0]["a"] = 1000
    mapSlice[0]["b"] = 2000
    mapSlice[0]["c"] = 3000
    mapSlice[0]["d"] = 4000
    mapSlice[0]["e"] = 5000
    fmt.Println("after map init")
    for index, value := range mapSlice {
      fmt.Printf("index:%d value:%v\n", index, value)
    }
  }
  
// before map init
// index:0 value:map[]
// index:1 value:map[]
// index:2 value:map[]
// index:3 value:map[]
// index:4 value:map[]
// after map init
// index:0 value:map[a:1000 b:2000 c:3000 d:4000 e:5000]
// index:1 value:map[]
// index:2 value:map[]
// index:3 value:map[]
// index:4 value:map[]

Go 面向对象编程

  • struct声明和定义

Go中⾯向对象是通过struct来实现的, struct是用户⾃定义的类型 , 注意:type是⽤来定义⼀种类型

 type User struct {
     Username  string
     Sex       string
     Age       int
     AvatarUrl string
 }

初始化 方法分为两种:

方法一:

注意:使⽤变量名+ ‘.’ + 字段名访问结构体中的字段
var user User
user.Age = 18
user.Username = “user01”
user.Sex = “男”
user.AvatarUrl = “http://my.com/xxx.jpg"

方法二:

var user User = User {
  “Username” : “user01”,
  “Age”: 18,
  “Sex”: “男”,
  “AvatarUrl”: “http://my.com/xxx.jpg”,
}

更简单的写法:

 user := User {
   “Username” : “user01”,
   “Age”: 18,
   “Sex”: “男”,
   “AvatarUrl”: “http://my.com/xxx.jpg”,
}
  • struct初始化的默认值是什么?
  var user User
  fmt.Printf(“%#v\n”, user)
  • 结构体类型的指针

注意:&User{}和new(User) 本质上是⼀样的,都是返回一个 结构体的地址

package mainimport ("fmt"

func main() {  
  var user *User = &User{}     
  fmt.Printf(“%p %#v\n”, user)

  // 直接初始化:

  var user *User = &User {
    Username : “user01”,
    Age: 18,
    Sex: “男”,
    AvatarUrl: “http://my.com/xxx.jpg”,
  }

  // 或者使用new
  var user User = new(User)
    user.Age = 18
    user.Username = “user01”
    user.Sex = “男”
    user.AvatarUrl = “http://my.com/xxx.jpg"
  }
  • 结构体的内存布局: 占⽤⼀段连续的内存空间
72d770f5dc7809ba66da9fc6240aa8b1.png
  • 结构体没有构造函数, 必要时需要⾃⼰实现

  • 匿名字段: 即没有名字的字段      注意:匿名字段默认采用类型名作为 字段名

 type User struct {
     Username  string
     Sex       string
     Age int
     AvatarUrl string
 }
 
type User struct {
    Username  string
    Sex       string   
    Age int
    AvatarUrl string
    int
    string
}
  • 结构体嵌套
type Address struct {
     City           string
     Province       string
 }

type User struct {
     Username  string
     Sex       string
     Age int
     AvatarUrl string
     address *Address
}     

func main () {
  user := &User {
    Username: 'user01',
    Sex: 'man',
    address: &Address {
      Province: 'beijing',
      City: 'beijing',
    },
  }
}
  • 匿名结构体

第二种方式 先在结构体里面找Provice以及City,如果结构体里面没有,则在匿名结构体里面找,

type Address struct {
     City           string
     Province       string
}
type User struct {
    Username  string
    Sex       string
    Age int
    AvatarUrl string
    *Address
}
func main () {
    var user User
    user.Username = 'user01'
    user.Sex = 'man'
    // 第一种方式
    user.Address = &Address{
       Provice: 'bj',
       City: 'bj'
    }
   // 第二种方式
   user.Province = 'bj01'
   user.City = 'bj01'
}
  • 匿名结构体的冲突解决 使用结构体的字段,如果结构体字段有值,则使用结构体,如果没有则使用匿名结构体的字段 如果两个匿名结构体都有相同的字段,当访问这个相同字段时候,要指定访问那个匿名结构体的字段
package mainimport ("fmt"
)
type Address struct {
  City   string
  Province string
  CreateTime string
}

type Email struct {
  Account  string
  CreateTime  string
}

type User struct { 
  Username  string
  Sex       string
  Age int
  AvatarUrl string
  *Address
  *Email
  CreateTime string
}


func main (){
  var user User
  user.Username = "user01"
  user.Sex = "man"
  user.City = "bj"
  user.Address = new(Address)
  user.Email = new(Email)
  user.Address.City ="bj01"
  user.Address.CreateTime ="001"
  user.Email.CreateTime = "002"
  fmt.Println( user.Email.CreateTime, user.Address.CreateTime)
}
  
  • 字段可⻅性,⼤写表示可公开访问,⼩写表示私有
type User struct {
    Username string
    Sex string
    Age int
    avatarUrl string // 私有
    CreateTime string
}
  • tag是结构体的元信息,可以在运行的时候通过反射的机制读取出来 字段类型后⾯,以反引号括起来的 key-value结构的字符串,多个tag 以逗号隔开。
type User struct { 
    Username  string   `json:”username”,db:”user_name”`
    Sex       string   `json:”sex”`   
    Age       int      `json:”age”`
    avatarUrl string
    CreateTime string
}

Go 方法的定义

  • 和其他语⾔不⼀样,Go的⽅法采⽤另外⼀种⽅式实现

  • Go的⽅法是在函数前⾯加上一个接受者,这样编译器就知道这个⽅法属于哪个类型了

f920cab3fe703922dfe203c0161bbb3b.png
  • 可以为当前包内定义的任何类型增加方法
6823a8fec6ebf5657fd8d2bef3bcc3e6.png
  • 函数和方法的区别: 函数不属于任何类型,⽅法属于特定的类型
  • 指针类型作为接受者995be4086de67ac1da137e75ed317367.png
  • 指针类型和值类型作为接受者的区别
值类型:

type People struct {
  Name  string
  Country string
}
func (p People) Print() {
  fmt.Println("name=%s country=%s\n",p.Name, p.Country)
}

func (p People) Set(name string, country string) {
  p.Name = name
  p.Country = country
}
func main() {
  var p1 People = People {
    Name: "people01",
    Country: "china",
  }
  p1.Print()  //  people01 china
  p1.Set("people02","english")
  p1.Print() // 不变 p是实例的拷贝   people01 china
}
 
 
指针类型:
type People struct {
  Name  string
  Country string
}
func (p People) Print() {
  fmt.Println("name=%s country=%s\n",p.Name, p.Country)
}
// 值类型
func (p People) Set(name string, country string) {
  p.Name = name
  p.Country = country
}
// 引用类型
func (p *People) SetV2(name string, country string) {
  p.Name = name
  p.Country = country
 }
func main() {
  var p1 People = People {
    Name: "people01",
    Country: "china",
  }
  p1.Print()  //  people01 china
  p1.Set("people02","english")
  p1.Print() // 不变 p是实例的拷贝   people01 china
  (&p1).SetV2("people02","english")或 语法糖: p1.SetV2("people02","english")
  p1.Print() // 变了 people02 english
}
 
  • 什么时候用值类型/指针类型作为接受者?

a. 需要修改接受者中的值的时候 b. 接受者是⼤对象的时候,副本拷贝代价⽐较大 c. ⼀般来说,通常使⽤指针类型作为接受者

  • 匿名结构体与继承

通过组合 和 匿名字段实现的继承,方法的冲突解决和匿名字段的冲突解决一致,都是通过指定对应的实例的方法解决

type Anaimal struct {
  Name  string
  Sex string
}
func (a *Anaimal) Talk() {
  fmt.Println(a.Name)
}

type Dog struct {
  Feet string
  *Anaimal
}

func (d *Dog) Eat () {
  fmt.Println("dog is eat")
}

func main () {
  var d *Dog = &Dog{
    Feet: "Four Feet",
    Anaimal: &Anaimal {
      Name: "dog",
      Sex: "xiong",
    },
  }
  d.Name = "dog"
  d.Sex = "xiong"
  d.Eat()
  d.Talk()

}


  • 多重继承与冲突解决
type Mother struct {
     Name string
 }
 type Father struct {
     Name string
 }

 type People struct {
    Sex       string
    Age int
    *Mother
    *Father
 }
  • 结构体与json序列列化
package mainimport ("encoding/json""fmt"
)
type Student struct {
   Id   string
   Name string
   Sex  string
}

type Class struct {
   Name     string
   Count    int
   Students []*Student
}

var rawJson = `
{"Name":"101","Count":0,"Students":[{"Id":"0","Name":"stu0","Sex":"man"},{"Id":"1","Name":"stu1","Sex":"man"},{"Id":"2","Name":"stu2","Sex":"man"},{"Id":"3","Name":"stu3","Sex":"man"},{"Id":"4","Name":"stu4","Sex":"man"},{"Id":"5","Name":"stu5","Sex":"man"},{"Id":"6","Name":"stu6","Sex":"man"},{"Id":"7","Name":"stu7","Sex":"man"},{"Id":"8","Name":"stu8","Sex":"man"},{"Id":"9","Name":"stu9","Sex":"man"}]}
`

func main() {
   c := &Class{
      Name:  "101",
      Count: 0,
   }

   for i := 0; i 10; i++ {
      stu := &Student{
         Name: fmt.Sprintf("stu%d", i),
         Sex:  "man",
         Id:   fmt.Sprintf("%d", i),
      }
      c.Students = append(c.Students, stu)
   }

   data, err := json.Marshal(c)
   if err != nil {
      fmt.Println("json marshal failed")
      return
   }

   fmt.Printf("json:%s\n", string(data))

   //json反序列化
   fmt.Println("unmarshal result is \n\n")
   var c1 *Class = &Class{}
   err = json.Unmarshal([]byte(rawJson), c1)
   if err != nil {
        fmt.Println("unmarhsal failed")
        return
   }
   fmt.Printf("c1:%#v\n", c1)
   for _, v := range c1.Students {
        fmt.Printf("stu:%#v\n", v)
   }
}

推荐阅读

(点击标题可跳转阅读)

RxJS入门

一文掌握Webpack编译流程

一文深度剖析Axios源码

Javascript条件逻辑设计重构
Promise知识点自测你不知道的React Diff你不知道的GIT神操作程序中代码坏味道(上)

程序中代码坏味道(下)

学习Less,看这篇就够了

一文掌握GO语言实战技能(一)

一文掌握Linux实战技能-系统管理篇

一文掌握Linux实战技能-系统操作篇

一文达到Mysql实战水平

一文达到Mysql实战水平-习题答案

从表单抽象到表单中台

vue源码分析(1)- new Vue

实战LeetCode 系列(一) (题目+解析)

一文掌握Javascript函数式编程重点

实战LeetCode - 前端面试必备二叉树算法

一文读懂 React16.0-16.6 新特性(实践 思考)

阿里、网易、滴滴、今日头条、有赞.....等20家面试真题

30分钟学会 snabbdom 源码,实现精简的 Virtual DOM 库


觉得本文对你有帮助?请分享给更多人

关注「React中文社区」加星标,每天进步

cc9127725708ab0c79e99ef2cc101785.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/575931.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

设置固定长度_加气块砌筑(构造柱、圈梁设置)技术交底21条

墙体砌筑技术交底我给下发21条,内容不全,砌筑的墙体观感差,欢迎大家提出宝贵意见1、填充墙的材料、平面位置尺寸见建筑施工图纸,不得随意更改。2、当首层填充墙下无基础梁或结构梁板时,墙下应做基础,基础作…

深度优化LNMP之MySQL

MySQL数据库优化框架体系 1.硬件层面优化 2.操作系统层面优化 3.MySQL数据库层面优化 4.MySQL安全优化 5.网站集群架构上的优化 6.MySQL流程、制度控制优化 硬件层面优化 1、数据库物理机采购 CPU: 64位CPU,一台机器2-16颗CPU。至少2-4颗&#xff0…

element vue 纵向滑动条_Vue 部分

1、ES6Vue :1、Vue 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的…

C#集合通论

前言 写这篇文章的最初动力是来自于一次笔试经历。有一道笔试题大概是这样的:程序使用一个txt文件来存储操作记录。存储记录是多行字符串,每一行代表一次操作记录,格式如下:用户名操作事项名称操作时间。现在假设这个txt文件已经非…

Shell 脚本案例实战 [4]

for循环结构for 循环结构语句1.for循环结构:语法:for 变量名 in 变量取值列表do指令…done提示:在此结构中“in 变量取值列表”可省略,省略时相当于in “$”,使用for i 就相当于使用for i in “$”2.C语言型for循环结构…

深度优化LNMP之PHP

PHP缓存加速介绍1.操作码介绍及缓存原理当客户端请求一个php程序时,服务器的PHP引擎会解析该PHP程序,并将其编译为特定的操作码文件(Operate Code,opcode)该文件是执行PHP代码后的一种二进制表示形式。默认情况下,这个…

PHP服务Fcgi进程及PHP解析优化

1、PHP引擎缓存加速常见四种软件:1.eAccelerator2.Zendcache3.xcache4.apc5.zendopcache php5.5自带2、使用tmpfs作为缓存加速缓存的文件目录 [rootweb02 ~]# mount -t tmpfs tmpfs /dev/shm -o size256m[rootweb02 ~]# mount -t tmpfs /dev/shm/ /tmp/eaccelerator…

电路 晶振频率_都说晶振是电路的心脏,你真的了解它吗?

之所以说晶振是数字电路的心脏,就是因为所有的数字电路都需要一个稳定的工作时钟信号,最常见的就是用晶振来解决,可以说只要有数字电路的地方就可以见到晶振。常见种类我们常说的晶振,包含两种。一种需要加驱动电路才能产生频率信…

ios 数组中的字典排序_利用数组和字典,实现按指定规则的排序

大家好,今日我们继续讲解数组与字典解决方案,今日讲解第47讲:利用字典和数组,实现按指定规则的排序。随着字典讲解的深入,我们发现字典真的很神奇,在VBA代码中,给人以十分清爽的感觉,在这套数组与字典解决方案中,我会尽可能的把经…

MVC3学习:利用mvc3+ajax实现登录

用到的工具或技术:vs2010,EF code first,JQuery ajax,mvc3。 第一步:准备数据库。 利用EF code first,先写实体类,然后根据实体类自动创建数据库;或者先创建数据库,再写实体类,都可以。如果实体…

vue获取tr内td里面所有内容_vue 项目学习

首先页面的整体内容结构以及package.json 里面的内容package.jsonrouter.js 路由功能import Vue from vue import Router from vue-router import Login from /login;Vue.use(Router) let router new Router({routes: [{path: /,redirect: {name: Login},},{path: /Login,na…

ubuntu中解压rar文件遇到乱码的解决方法

如上图所示,在用ubuntu的时候经常会遇见rar压缩文件打开出现乱码,解压的时候也会出现无效的编码等错误。 解决方法是用 sudo apt-get remove rar 卸载rar 然后用 sudo apt-get instal unrar 安装unrar 然后就可以解决这个问题了。 个人理解rar是用来压缩…

kmeans中的k的含义_硬质合金中P、M、K、N、S、H六大字母含义详解

数控技术在线订单 | 技术 | 干货 | 社群关注可加入机械行业群!关注P类:硬质合金中,P类产品的切削范围是指碳钢,铸钢,包括0.25-0.25%C淬火和调质,易切钢包含退火与淬火调质,低碳合金钢含金元素少于5%的范围&…

gitlab集成ldap用户后,禁用原来的账户体系进行拉取代码

gitlab在集成ldao用户后,经过测试,用户可以还可以通过原来的账号体系进行项目代码的拉取,需要把原来的账号体系的拉取功能关闭,使用ldap的账号体系进行工作开展。 方法如下: 在管理员-设置-通用-登录限制里把 Allow…

ffmpeg 分辨率 压缩_用GPU加速FFmpeg中的超分辨率功能

1. 简要回顾首先简单复述一下FFmpeg中对深度学习的支持情况,如上图所示,FFmpeg在libavfilter中支持基于深度学习的filter,目前已经支持sr, derain和dnn_processing等filter,其中,dnn_processing是一个通用的filter&…

mysql存储过程输入参数拆分_一文看懂mysql数据库存储过程、函数、视图、触发器、表...

概述抽空总结一下mysql的一些概念性内容,涉及存储过程、函数、视图、触发器等。一、查看存储过程、函数、视图、触发器、表1、存储过程select * from mysql.proc where typePROCEDURE;show procedure status; show create procedure proc_name; //存储过程定义2、函…

oracle vm发现无效设置_Oracle数据库编译失效对象相关命令总结大全,值得收藏

概述在日常数据库维护过程中,我们会发现数据库中一些对象(包Package、存储过程Procedure、函数Function、视图View、同义词.....)会失效,呈现无效状态(INVALID)。有时候需要定期检查数据库中存在哪些失效对象,对于存在异常的对象需要重新编译&#xff0c…

WCF-001:WCF的发布

随着“云”时代的到来,“云”已经无处不在了。什么是“云”,无非就是利用互联网强大的功能建立多个服务器,然后再利用互联网的传输数据的特点将数据从某个服务器中读取出来或者将你的数据上传上去。当然这个服务器不是一定就是传统意义的服务…

在线编辑_水墨-在线 Markdown 编辑器

水墨-在线 Markdown 编辑器基于 Spring-boot、FreeMarker、layui、Vditor 构建的一款在线 所见即所得的 Markdown 编辑器。水墨-在线 Markdown 编辑器。本人使用 Vditor 编辑器时日已久,眼看着其功能日益强大,特此基于 Vditor 构建一款 Web 编辑器&#…

退出出库复核是什么意思_细思极恐!为什么是黄晓明退出而不是李菲儿?因为女方是芒果艺人...

本文转载自:娱评人吴清功序言:《乘风破浪的姐姐》第二季即将接档《姐姐的爱乐之程》,于每周五晚上十点档播出。2021年1月5日,《乘风破浪的姐姐2》第一次公演举行,选手李菲儿和发起人黄晓明有亲密互动,李菲儿…