2022年8月

type关键字可以用于定义任何自定义类型,比如常见的

type st1 struct{
}
type ani int

也可以用来起别名

type intalias int // intalias类型是int类型的别名

type func



讲typefunc讲的非常好的一片博客

type myFunc func(int) int的意思是,定义一个叫做myFunc的函数类型,他的格式是func(int) int,只要输入输出符合这个格式的函数,都能强制类型转换成myFunc类,如

type myFunc func(int) int
 
 
func sum10(num int) int {
    fmt.Println(num*10)
}
 
 
func main() {
    newFunc := myFunc(sum10) // 这里把sum10强制类型转换为myFunc
}

这个别名的方式可以帮助我们方便的使用接口和重载,如下

type sumable interface {  //定义了一个叫做sumable的接口,拥有sum方法
    sum(int, int) int
}
 
// myFunc继承sumable接口
type myFunc func(int) int  //定义了一个叫做myFunc的函数类型,格式为func(int) int
 
func (f myFunc) sum (a, b int) int {  //给myFunc类型增加sum实现方法,只要是myFunc类都能调用这个方法
    res := a + b
    return f(res) //这里返回f(res),即myFunc(res),也就是调用下面被强制转换成myFunc的那些函数自己本身
}
 
func sum10(num int) int {  //定义了两个函数,类型都是func(int) int,符合myFunc,可以被强制类型转换
    return num * 10
}
 
func sum100(num int) int {
    return num * 100
}
 
// icansum结构体继承sumable接口
type icansum struct {  //定义了一个叫做icansum的结构类型
    name string
    res int
}
 
func (ics *icansum) sum(a, b int) int { //给icansum结构类型添加了sum方法
    ics.res = a + b
    return ics.res
}
 
// handler只要是继承了sumable接口的任何变量都行,我只需要你提供sum函数就好
func handlerSum(handler sumable, a, b int) int {  //定义了一个handlerSum,传入了一个sumable,只要这个实例实现了sum方法就能被调用
    res := handler.sum(a, b) //调用这个实例的sum方法
    fmt.Println(res)
    return res
}
 
func main() {
    newFunc1 := myFunc(sum10) //先把sum10类型转换为myFunc,然后赋值给newFunc1
    newFunc2 := myFunc(sum100)
 
    handlerSum(newFunc1, 1, 1)    // 20 调用newFunc1的sum方法,即第八行,先a+b=2,然后再newFunc1(2),即sum10(2)
    handlerSum(newFunc2, 1, 1)    // 200
 
    ics := &icansum{"I can sum", 0} //实例化一个icansum
    handlerSum(ics, 1, 1)         // 2  调用icansum的sum方法,即27行的函数,a+b=2
}

JSON是一种受到广泛支持的语言格式,JSON里一个对象是一个字符串到值的映射,用花括号和逗号分隔,JSON在go里面可以被用来编写map和结构体,譬如

type Movie struct {
    Title  string
    Year   int  `json:"released"` //编码后名称变为released,不加默认用成员名
    Color  bool `json:"color,omitempty"`//编码后改名外加如果是空的那么不显示
    Actors []string
}

var movies = []Movie{
    {Title: "Casablanca", Year: 1942, Color: false,
        Actors: []string{"Humphrey Bogart", "Ingrid Bergman"}},
    {Title: "Cool Hand Luke", Year: 1967, Color: true,
        Actors: []string{"Paul Newman"}},
    {Title: "Bullitt", Year: 1968, Color: true,
        Actors: []string{"Steve McQueen", "Jacqueline Bisset"}},
    // ...
}

使用json.Marshal和json.MarshalIndent,前者返回一个slice,没有缩进,后者带两个参数,可以控制每一行的输出的前缀和每一段的缩进

data, err := json.MarshalIndent(movies, "", "    ")
if err != nil {
    log.Fatalf("JSON marshaling failed: %s", err)
}
fmt.Printf("%s\n", data)

输出

[
    {
        "Title": "Casablanca",
        "released": 1942,
        "Actors": [
            "Humphrey Bogart",
            "Ingrid Bergman"
        ]
    },
    {
        "Title": "Cool Hand Luke",
        "released": 1967,
        "color": true,
        "Actors": [
            "Paul Newman"
        ]
    },
    {
        "Title": "Bullitt",
        "released": 1968,
        "color": true,
        "Actors": [
            "Steve McQueen",
            "Jacqueline Bisset"
        ]
    }
]

解码使用unmarshaling解码成切片,可以选择性解码,即只解出需要的值

var titles []struct{ Title string }
if err := json.Unmarshal(data, &titles); err != nil {
    log.Fatalf("JSON unmarshaling failed: %s", err)
}
fmt.Println(titles) // "[{Casablanca} {Cool Hand Luke} {Bullitt}]"

type any added in go1.18

type any = interface{}
any is an alias for interface{} and is equivalent to interface{} in all ways

any是空接口的别名,在go1.18后引入

接口是两件事物:它是一组方法,也是一种类型。
interface{} 类型是没有方法的接口。由于没有 implements 关键字,所有类型都至少实现零个方法,并且自动满足接口,所有类型都满足空接口,所以空接口能够被用来存储任意类型的值


inerface{}底层实现

type emptyInterface struct {
   typ  *rtype            // 类型描述
   Word unsafe.Pointer    // 值
}

可以看到其包含一个类型描述和一个值

type rtype struct {
   size       uintptr
   ptrdata    uintptr
   hash       uint32
   tflag      tflag
   align      uint8
   fieldAlign uint8
   kind       uint8
   alg        *typeAlg
   gcdata     *byte
   str        nameOff
   ptrToThis  typeOff
}

空接口嵌入的类型,我们可以映射导出字段或列出方法

package main

import "fmt"

type Set map[string]struct{} //空struct不占空间

func main() {
    s := make(Set)
    s["zhangsan"] = struct{}{}
    s["lisi"] = struct{}{}
    s["wangwu"] = struct{}{}
    fmt.Println(get_value(s))
}

func get_value(s Set) []string {
    var setvalue []string
    for key, _ := range s {
        setvalue = append(setvalue, key)
    }
    return setvalue
}

map的key无序、不重复,跟set有着很相似的特性,而空struct{}不占空间,用来填充值是最合适的,struct{}{}是一个复合字面量,他表示一个struct{}类型的值,因为是字面量(除了数字以外的常量),所以所有struct{}{}指向同一个位置