golang基础(1)https://developer.aliyun.com/article/1530648
结构体
package main import "fmt" type user struct { name string password string } func main() { a := user{name: "wang", password: "1024"} b := user{"wang", "1024"} c := user{name: "wang"} c.password = "1024" var d user d.name = "wang" d.password = "1024" fmt.Println(a, b, c, d) // {wang 1024} {wang 1024} {wang 1024} {wang 1024} fmt.Println(checkPassword(a, "haha")) // false fmt.Println(checkPassword2(&a, "haha")) // false } func checkPassword(u user, password string) bool { return u.password == password } func checkPassword2(u *user, password string) bool { return u.password == password }
结构体实现继承需要在子结构体里添加父类的结构体,但好像,并不能通过这种方式进行多态,多态只能通过接口
结构体方法
package main import "fmt" type user struct { name string password string } func (u user) checkPassword(password string) bool { return u.password == password } func (u *user) resetPassword(password string) { u.password = password } func main() { a := user{name: "wang", password: "1024"} a.resetPassword("2048") fmt.Println(a.checkPassword("2048")) // true }
第一个不带指针,是结构体的副本,第二个带指针 ,和传统方法相比应该是这款把结构体放在了func后面
如果结构体里面属性名称首字母小写,则只能在结构体内部使用相当于私有属性,大写则可以外部调用
结构体方法大写则别的包也可以使用,不然只能在本包里面使用
接口
package main import "fmt" //接口 type Animal interface { Sleep() GetColor() string GetType() string } // type Cat struct { color string } type Dog struct { color string } func (this *Cat) Sleep() { fmt.Println("cat is sleep") } func (this *Cat) GetColor() string { return this.color } func (this *Cat) GetType() string { return "Cat" } func (this *Dog) Sleep() { fmt.Println("dog is sleep") } func (this *Dog) GetColor() string { return this.color } func (this *Dog) GetType() string { return "Dog" } func showAnimal(animal Animal) { animal.Sleep() } func main() { cat := &Cat{"Green"} dog := &Dog{"BLACK"} showAnimal(cat) showAnimal(dog) }
实现接口只需要结构体方法和接口里面定义的方法一样即可,然后接口本身是一个指针类型,所以要复制给他的是结构体实例的引用
空接口和断言
interface{}
- 空接口
- int,string,float32,float64,struct 都实现了interface{}
- 就可以用interface{} 类型引用任意的数据类型
这里value是值,ok是是否为某个类型
package main import "fmt" func myFun(arg interface{}) { fmt.Println(arg) fmt.Printf("%T\n", arg) value, ok := arg.(int) if !ok { fmt.Println("is not string", value) fmt.Printf("type is %T", value) } else { fmt.Println("arg is ", value) fmt.Printf("type is %T", value) } } func main() { myFun(11) }
Golang的语言中提供了断言的功能。golang中的所有程序都实现了interface{}的接口,这意味着,所有的类型如string,int,int64甚至是自定义的struct类型都就此拥有了interface{}的接口,这种做法和java中的Object类型比较类似。那么在一个数据通过func funcName(interface{})的方式传进来的时候,也就意味着这个参数被自动的转为interface{}的类型。
//这种使用方式会出问题,但是可以直接使用a,或者断言 func funcName(a interface{}) string { return string(a) }
配合switch使用
var t interface{} t = functionOfSomeType() switch t := t.(type) { default: fmt.Printf("unexpected type %T", t) // %T prints whatever type t has case bool: fmt.Printf("boolean %t\n", t) // t has type bool case int: fmt.Printf("integer %d\n", t) // t has type int case *bool: fmt.Printf("pointer to boolean %t\n", *t) // t has type *bool case *int: fmt.Printf("pointer to integer %d\n", *t) // t has type *int }
r=Book类型,BOOK实现了Reader和Writer,所以r能断言Witter成功,这里是有点类似实现了多个接口,指向他的父类型是哪个就可以使用哪个父接口定义的方法
但是只有接口才能断言
反射
变量的结构
var a string //pair<statictype:string,value:"aceld"> a = "aceld" //pair<type:string,value:"aceld"> var allType interface{} allType = a
r=Book类型,BOOK实现了Reader和Writer,所以r能断言Witter成功
编程语言中反射的概念
在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
每种语言的反射模型都不同,并且有些语言根本不支持反射。Golang语言实现了反射,反射机制就是在运行时动态的调用对象的方法和属性,官方自带的reflect包就是反射相关的,只要包含这个包就可以使用。
多插一句,Golang的gRPC也是通过反射实现的。
interface 和 反射
在讲反射之前,先来看看Golang关于类型设计的一些原则
●变量包括(type, value)两部分
●type 包括 static type和concrete type. 简单来说 static type是你在编码是看见的类型(如int、string),concrete type是runtime系统看见的类型
●类型断言能否成功,取决于变量的concrete type,而不是static type. 因此,一个 reader变量如果它的concrete type也实现了write方法的话,它也可以被类型断言为writer.
接下来要讲的反射,就是建立在类型之上的,Golang的指定类型的变量的类型是静态的(也就是指定int、string这些的变量,它的type是static type),在创建变量的时候就已经确定,反射主要与Golang的interface类型相关(它的type是concrete type),只有interface类型才有反射一说。
在Golang的实现中,每个interface变量都有一个对应pair,pair中记录了实际变量的值和类型:
Golang的反射reflect
reflect的基本功能TypeOf和ValueOf
既然反射就是用来检测存储在接口变量内部(值value;类型concrete type) pair对的一种机制。那么在Golang的reflect反射包中有什么样的方式可以让我们直接获取到变量内部的信息呢? 它提供了两种类型(或者说两个方法)让我们可以很容易的访问接口变量内容,分别是reflect.ValueOf() 和 reflect.TypeOf(),
说明
- reflect.TypeOf: 直接给到了我们想要的type类型,如float64、int、各种pointer、struct 等等真实的类型
- reflect.ValueOf:直接给到了我们想要的具体的值,如1.2345这个具体数值,或者类似&{1 “Allen.Wu” 25} 这样的结构体struct的值
- 也就是说明反射可以将“接口类型变量”转换为“反射类型对象”,反射类型指的是reflect.Type和reflect.Value这两种
从relfect.Value中获取接口interface的信息
当执行reflect.ValueOf(interface)之后,就得到了一个类型为”relfect.Value”变量,可以通过它本身的Interface()方法获得接口变量的真实内容,然后可以通过类型判断进行转换,转换为原有真实类型。不过,我们可能是已知原有类型,也有可能是未知原有类型,因此,下面分两种情况进行说明。
已知原有类型【进行“强制转换”】
已知类型后转换为其对应的类型的做法如下,直接通过Interface方法然后强制转换,如下:****
realValue := value.Interface().(已知的类型)
package main import ( “fmt” “reflect” ) func main() { var num float64 = 1.2345
pointer := reflect.ValueOf(&num) value := reflect.ValueOf(num) // 可以理解为“强制转换”,但是需要注意的时候,转换的时候,如果转换的类型不完全符合,则直接panic // Golang 对类型要求非常严格,类型一定要完全符合 // 如下两个,一个是*float64,一个是float64,如果弄混,则会panic convertPointer := pointer.Interface().(*float64) convertValue := value.Interface().(float64) fmt.Println(convertPointer) fmt.Println(convertValue)
}
运行结果:
0xc42000e238
1.2345
反射解析结构体标签
主要用来结构体说明
package main import ( "fmt" "reflect" ) type resume struct { Name string `json:"name" doc:"我的名字"` } func findDoc(stru interface{}) map[string]string { t := reflect.TypeOf(stru).Elem() doc := make(map[string]string) for i := 0; i < t.NumField(); i++ { doc[t.Field(i).Tag.Get("json")] = t.Field(i).Tag.Get("doc") } return doc } func main() { var stru resume doc := findDoc(&stru) fmt.Printf("name字段为:%s\n", doc["name"]) }
error
package main import ( "errors" "fmt" ) type user struct { name string password string } func findUser(users []user, name string) (v *user, err error) { for _, u := range users { if u.name == name { return &u, nil } } return nil, errors.New("not found") } func main() { u, err := findUser([]user{{"wang", "1024"}}, "wang") if err != nil { fmt.Println(err) return } fmt.Println(u.name) // wang if u, err := findUser([]user{{"wang", "1024"}}, "li"); err != nil { fmt.Println(err) // not found return } else { fmt.Println(u.name) } }
string
package main import ( "fmt" "strings" ) func main() { a := "hello" fmt.Println(strings.Contains(a, "ll")) // true fmt.Println(strings.Count(a, "l")) // 2 fmt.Println(strings.HasPrefix(a, "he")) // true fmt.Println(strings.HasSuffix(a, "llo")) // true fmt.Println(strings.Index(a, "ll")) // 2 fmt.Println(strings.Join([]string{"he", "llo"}, "-")) // he-llo fmt.Println(strings.Repeat(a, 2)) // hellohello fmt.Println(strings.Replace(a, "e", "E", -1)) // hEllo fmt.Println(strings.Split("a-b-c", "-")) // [a b c] fmt.Println(strings.ToLower(a)) // hello fmt.Println(strings.ToUpper(a)) // HELLO fmt.Println(len(a)) // 5 b := "你好" fmt.Println(len(b)) // 6 }
golang基础(3)https://developer.aliyun.com/article/1530655