type和string

1.认识type关键字

type不光能定义结构体,接口还能定义自己的类型,比如说我定义一个自己的String

type String string

//构造函数 From写法其他编程语言比较常见
func From(str string) String{
    return String(str)
}

func main() {
    s := String.From("abc")
}

2.自己的String:类型方法 int变string

type String string

//构造函数 From写法其他编程语言比较常见
func FromInt(n int) String{
    // return String(n)    //错误写法
    // return String(strconv.Itoa(n)) //使用strconv包下的方法将int转换为string
    return String(fmt.Sprintf("%d",n)) //格式化,并把格式化内容返回 推荐这么写 也很好理解
}

// 返回长度
func (s String) Len() int {
    return len(s)
}

func main() {
    s := String.From(123)
    fmt.Ptintln(s,s.Len())  
    //return String(n)  输出了'{' 这个符号刚好是ASCII码对应的123 说明了不行直接return String(n)不行    
}
123 3

3.自己的String:遍历字符串 Each(*

type String string

//构造函数 From写法其他编程语言比较常见
func From(str string) String{
    return String(str)
}

//模仿Js 类函数 函数式参数,传的是一个函数
func (s String) Each(f func(item string))  {
    for i := 0; i < len(s); i++ {
        //fmt.Println(i,"",fmt.Sprintf("%c",str[i]))
        f(fmt.Sprintf("%c",s[i]))
    }
    //for _, c := range s {
    //    f(fmt.Sprintf("%c",c))
    //}
}


func main() {
    str := String.From("abcde")
    
    for i := 0; i < len(str); i++ {
        fmt.Println(i,"",fmt.Sprintf("%c",str[i]))
    }
    
    str.Each(func(item string) {
        fmt.Println(item)    
    })
}

4.自己的String:遍历字符串 (带中文)

一个中文字符占3个字节

type String string

//构造函数 From写法其他编程语言比较常见
func From(str string) String{
    return String(str)
}

//模仿Js 类函数 函数式参数,传的是一个函数
func (s String) Each(f func(item string))  {
    for _, c := range s {
        f(fmt.Sprintf("%c",c))
    }
}


func main() {
    str := String.From("中abc")
      
    str.Each(func(item string) {
        fmt.Println(item)    
    })
}
中
a
b
c

5.从字符串中再认识下byte、rune

一般进行网络传输的时候使用字节传输

byte = uint8 ,代表了ASCII码字符集的一个字符

rune = int32 ,当处理中文、日文、韩文等复合字符集时,使用rune 。也就是Unicode字符集(utf-8、utf16是编码规则)

自定义struct

6.自定义struct、构造函数

Go语言都是值传递

package Object

type User struct {
    Id,Sex int
    Name string
 }

func NewUser() User {
    return User{}
}
func change(u Object.User) Object.User {
    u.Id = 202
    return u
}

func main() {
    u := Object.NewUser()
    u.Id = 101
    //一般代码不会这么写,通常使用指针
    u = change(u)
    //fmt.Println(u)
    fmt.Printf("%#v\n", &u)
}

7.使用指针struct

type User struct {
    Id,Sex int
    Name string
 }

func NewUser() *User {
    //两种写法
    return new(User)
    //return &User
}
func change(u *Object.User)  {
   u.Id = 202
   fmt.Printf("%p\n",u)
}

func main() {
   //uu := Object.User{}
   //fmt.Println(uu)  //{0 0 }
   //
   //u := Object.NewUser()
   //fmt.Println(u)  //&{0 0 }

   //var u1 Object.User
   //var u2 *Object.User
   //
   //fmt.Println(u1,u2)   //{0 0 } <nil>

   u := Object.NewUser()
   u.Id = 101
   
   change(u)
   fmt.Printf("%p\n", u)
}

8.构造函数的技巧:任意设置属性值(*

我之前的lowB写法

func NewUser(id int) User {
    return User{
        Id: id,
    }
}

带佬写法

type User struct {
    Id,Sex int
    Name string
 }

 //有选择性的对ID进行赋值

func NewUser(f func(u *User)) *User {
    u := new(User)
    f(u)
    return u
}
//WithUserID :NewUser 中 参数的构造函数
func WithUserID(id int) func(u *User) {
    return func(u *User) {
        u.Id = id
    }
}
func main() {
    u := Object.NewUser(
        Object.WithUserID(120),
    )
    fmt.Println(u) //&{120 0 }
}

9.构造函数技巧:可变参数(*)

上面的代码有一些小遗憾,参数是必填的,不填会报错,zhei次要使用可变参数

type User struct {
    Id,Sex int
    Name string
 }

 //有选择性的对ID进行赋值
//...表示可变参数,fs是一个切片
func NewUser(fs ... func(u *User)) *User {
    u := new(User)
    for _, f := range fs {
        f(u)
    }
    return u
}

//WithUserID :NewUser 中 参数的构造函数
func WithUserID(id int) func(u *User) {
    return func(u *User) {
        u.Id = id
    }
}

//缺点是代码量增加了,但是调用方便了

func WithUserNmae(name string) func(u *User) {
    return func(u *User) {
        u.Name = name
    }
}
func main() {
   //技术,两害取其精 看自己取舍了
   u := Object.NewUser(
      Object.WithUserNmae("Jahon"),
      //可以不填,也可以填
      Object.WithUserID(120),
   )
   fmt.Println(u) //&{120 0 }
}

10.构造函数技巧:进一步提升逼格(🐂的)

反复封装,绕的有些晕

package Object

import "fmt"

type UserAttrFunc func(*User) //用来设置user属性的 函数类型
type UserAttrFuncs []UserAttrFunc

// UserAttrFunc 的构造函数
func (this UserAttrFuncs) apply(u *User)  {
    //好比执行了 func(*User){} ()
    for _, f := range this {
        f(u)
    }
}

type User struct {
    Id,Sex int
    Name string
 }

 //有选择性的对ID进行赋值
//...表示可变参数,fs是一个切片

func NewUser(fs ... UserAttrFunc) *User {
    u := new(User)
    //这里需要进行一次强制转换
    UserAttrFuncs(fs).apply(u)

    fmt.Printf("%T\n",fs) //[]Object.UserAttrFunc 切片
    return u
}


//WithUserID :NewUser 中 参数的构造函数
func WithUserID(id int) UserAttrFunc {
    return func(u *User) {
        u.Id = id
    }
}

//缺点是代码量增加了,但是调用方便了

func WithUserNmae(name string) UserAttrFunc {
    return func(u *User) {
        u.Name = name
    }
}
func main() {
   //技术,两害取其精
   u := Object.NewUser(
      Object.WithUserNmae("Jathon"),
      //可以不填,也可以填
      Object.WithUserID(120),
   )
   fmt.Println(u) //&{120 0 }
}

map

11.基本使用、模拟User实体的创建

package Map

type User map[string]string

func NewUser() User {
   return make(map[string]string)
}
//map是引用类型,传的是地址的值,复制也是地址的值,所以可以直接改,没有必要写指针
func change(u Map.User)  {
   u["id"] = "404"
}
func main() {

   //map的 key值必须是可比较的
   //var user map[string]string
   //user = make(map[string]string)
   //user["id"] =  "101"
   //fmt.Println(user)
   u :=Map.NewUser()
   u["id"] = "101"
   u["name"] = "Jathon"
   fmt.Println(u) //map[id:101 name:Jathon]
   change(u)
   fmt.Println(u) //map[id:404 name:Jathon]
}

12.设置值、链式调用

package Map

type User map[string]interface{}

func NewUser() User {
   return make(map[string]interface{})
}
func (u User) With(k string,v interface{}) User {
   u[k] = v
   return u
}
func main() {
    //普通调用
    //func (u User) With(k string,v interface{}) {
    //  u[k] = v
    //}
    u :=Map.NewUser()
    u.With("id","101")
    u.With("name","Jathon")
    fmt.Println(u)

    //链式调用(比较特殊的写法)
    u.With("id","101").
      With("name","Jathon")
}

13.遍历map、按自己的格式打印map

func (u User) String() {
   for k, v := range u {
      fmt.Printf("%v->%v\n",k,v)
   }
}
func main() {
   u :=Map.NewUser()
   //链式调用
   u.With("id","101").
     With("name","Jathon")
   u.String()
}

下面这种算是种特殊的写法了,场景是老子偏要使用Println这种形式,它返回的是string,在运行Println时会主动调用这个方法。

func (u User) String() string {
   str := ""
   for k, v := range u {
      str+= fmt.Sprintf("%v->%v\n",k,v)
   }
   return str
}
func main() {
   u :=Map.NewUser()
   //链式调用
   u.With("id","101").
     With("name","Jathon")
   fmt.Println(u)
}

14.排序Map Key、Sort包初步使用

//思路是把map的key放到切片中,用sort包进行排序

func (u User) Fields() []string {
   keys :=[]string{}
   for k, _ := range u {
      keys = append(keys, k)
   }

   //1.0写法
   sort.Strings(keys)
   //更妥帖的写法(强转一下)
   sort.Strings(sort.StringSlice(keys))
   //点进sort包可以看到最原始写法(写全)
   sort.Sort(sort.StringSlice(keys))
   //倒排
   sort.Sort(sort.Reverse(sort.StringSlice(keys)))

   return keys
}

func (u User) String() string {
   str := ""
   for index, k := range u.Fields() {
      str+= fmt.Sprintf("%d、%v->%v\n",index+1,k,u[k])
   }
   return str
}
func main() {
   u := Map.NewUser()
   //链式调用
   u.With("id", "101").
      With("name", "Jathon").
      With("sex", "male").
      With("age", 18)
   fmt.Println(u)
}
1、sex->male
2、name->Jathon
3、id->101
4、age->18

15.多个map之间的排序方法

func main() {

    u1 := Map.NewUser()
    u1.With("id", "101").
        With("name", "Jathon").
        With("age", 18)

    u2 := Map.NewUser()
    u2.With("id", "114514").
        With("name", "李田所").
        With("age", 24)

    u3 := Map.NewUser()
    u3.With("id", "6324").
        With("name", "孙笑川").
        With("age", 33)

    users := []Map.User{}
    users = append(users, u1, u2, u3)

    //a, b   c=人类   断定c是a
    //i和j是索引
    //sort.Slice 不保证相等情况下顺序
    //sort.SliceStable 更严谨
    sort.SliceStable(users, func(i, j int) bool {
        //断言功能 专针对于interface 断言成int
        age1 := users[i]["age"].(int)
        age2 := users[j]["age"].(int)
        return age1 < age2
    })
    fmt.Println(users)
}

go test测试入门

16.编写最简单的单元测试代码

17.最简单点的表驱动测试代码

18.基准测试:快速使用

19.基准测试:优化优化字符串累加性能

interface和反射

20.理解interface、模拟用户服务

21.使用接口简化代码、链式调优

22.使用接口简化代码,传递接口参数和断言

23.反射入门、获取Struct所有属性、Elem函数

24.Kind函数、获取struct属性值的两种方式

25.利用反射设置Struct属性值、切片映射struct

26.【练习】把map映射成struct

27.把map映射成struct:支持tag参数

最后修改:2022 年 05 月 08 日
如果觉得我的文章对你有用,请随意赞赏