这里有新鲜出炉的 GO 语言教程,程序狗速度看过来!
Go 是一种新的语言,一种并发的、带垃圾回收的、快速编译的语言。Go 是谷歌 2009 年发布的第二款编程语言。2009 年 7 月份,谷歌曾发布了 Simple 语言,它是用来开发 Android 应用的一种 BASIC 语言。
下面小编就为大家带来一篇浅谈 Go 语言中的结构体 struct & 接口 Interface & 反射。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
结构体 struct
struct 用来自定义复杂数据结构,可以包含多个字段(属性),可以嵌套;
go 中的 struct 类型理解为类,可以定义方法,和函数定义有些许区别;
struct 类型是值类型。
struct 定义
- type User struct {
- Name string
- Age int32
- mess string
- }
- var user User
- var user1 * User = &User {}
- var user2 * User = new(User)
struct 使用
下面示例中 user1 和 user2 为指针类型,访问的时候编译器会自动把 user1.Name 转为 (*user1).Name
- func main() {
- var user User
- user.Name = "nick"
- user.Age = 18
- user.mess = "lover"
- var user1 *User = &User{
- Name: "dawn",
- Age: 21,
- }
- fmt.Println(*user1) //{dawn 21 }
- fmt.Println(user1.Name, (*user1).Name) //dawn dawn
- var user2 *User = new(User)
- user2.Name = "suoning"
- user2.Age = 18
- fmt.Println(user2) //&{suoning 18 }
- fmt.Println(user2.Name, (*user2).Name) //suoning suoning
- }
构造函数
golang 中的 struct 没有构造函数,可以伪造一个
- type User struct {
- Name string Age int32 mess string
- }
- func NewUser(name string, age int32, mess string) * User {
- return & User {
- Name: name,
- Age: age,
- mess: mess
- }
- }
- func main() {
- //user := new(User)
- user: =NewUser("suoning", 18, "lover") fmt.Println(user, user.mess, user.Name, user.Age)
- }
内存布局
struct 中的所有字段在内存是连续的
- var user User
- user.Name = "nick"
- user.Age = 18
- user.mess = "lover"
- fmt.Println(user) //{nick 18 lover}
- fmt.Printf("Name:%p\n", &user.Name) //Name:0xc420016180
- fmt.Printf("Age: %p\n", &user.Age) //Age: 0xc420016190
- fmt.Printf("mess:%p\n", &user.mess) //mess:0xc420016198 8字节为内存对齐
方法
方法是作用在特定类型的变量上,因此自定义类型,都可以有方法,而不仅仅是 struct。
方法的访问控制也是通过大小写控制。
init 函数是通过传入指针实现,这样改变 struct 字段值,因为是值类型。
- type User struct {
- Name string
- Age int
- sex string
- }
- func (this *User) init(name string, age int, sex string) {
- this.Name = name
- this.Age = age
- this.sex = sex
- }
- func (this User) GetName() string {
- return this.Name
- }
- func main() {
- var user User
- user.init("nick", 18, "man")
- //(&user).init("nick", 18, "man")
- name := user.GetName()
- fmt.Println(name)
- }
匿名字段
如果有冲突的, 则最外的优先
- type User struct {
- Name stirng
- Age int
- }
- type Lover struct {
- User
- sex time.Time
- int
- Age int
- }
继承 & 多重继承
一个结构体继承多个结构体,访问通过点。继承字段以及方法。
可以起别名,如下面 u1(user1),访问 user.u1.Age。
如果继承的结构体都拥有同一个字段,通过 user.name 访问就会报错,必须通过 user.user1.name 来访问。
- type user1 struct {
- name string
- Age int
- }
- type user2 struct {
- name string
- age int
- sex time.Time
- }
- type User struct {
- u1 user1 //别名
- user2
- Name string
- Age int
- }
- func main() {
- var user User
- user.Name = "nick"
- user.u1.Age = 18
- fmt.Println(user) //{{ 18} { 0 {0 0 <nil>}} nick 0}
- }
tag
在 go 中,首字母大小写有特殊的语法含义,小写包外无法引用。由于需要和其它的系统进行数据交互,例如转成 json 格式。这个时候如果用属性名来作为键值可能不一定会符合项目要求。tag 在转换成其它数据格式的时候,会使用其中特定的字段作为键值。
- import "encoding/json"
- type User struct {
- Name string `json:"userName"`
- Age int `json:"userAge"`
- }
- func main() {
- var user User
- user.Name = "nick"
- user.Age = 18
- conJson, _ := json.Marshal(user)
- fmt.Println(string(conJson)) //{"userName":"nick","userAge":0}
- }
String()
如果实现了 String() 这个方法,那么 fmt 默认会调用 String()。
- type name1 struct {
- int
- string
- }
- func (this *name1) String() string {
- return fmt.Sprintf("This is String(%s).", this.string)
- }
- func main() {
- n := new(name1)
- fmt.Println(n) //This is String().
- n.string = "suoning"
- d := fmt.Sprintf("%s", n) //This is String(suoning).
- fmt.Println(d)
- }
接口 Interface
Interface 类型可以定义一组方法,但是这些不需要实现。并且 interface 不能包含任何变量。
interface 类型默认是一个指针。
Interface 定义
- type Car interface {
- NameGet() string
- Run(n int)
- Stop()
- }
Interface 实现
Golang 中的接口,不需要显示的实现。只要一个变量,含有接口类型中的所有方法,那么这个变量就实现这个接口。因此,golang 中没有 implement 类似的关键字;
如果一个变量含有了多个 interface 类型的方法,那么这个变量就实现了多个接口;如果一个变量只含有了 1 个 interface 的方部分方法,那么这个变量没有实现这个接口。
空接口 Interface{}:空接口没有任何方法,所以所有类型都实现了空接口。
- var a int
- var b interface {} //空接口
- b = a
多态
一种事物的多种形态,都可以按照统一的接口进行操作。
栗子:
- type Car interface {
- NameGet() string Run(n int) Stop()
- }
- type BMW struct {
- Name string
- }
- func(this * BMW) NameGet() string {
- return this.Name
- }
- func(this * BMW) Run(n int) {
- fmt.Printf("BMW is running of num is %d \n", n)
- }
- func(this * BMW) Stop() {
- fmt.Printf("BMW is stop \n")
- }
- type Benz struct {
- Name string
- }
- func(this * Benz) NameGet() string {
- return this.Name
- }
- func(this * Benz) Run(n int) {
- fmt.Printf("Benz is running of num is %d \n", n)
- }
- func(this * Benz) Stop() {
- fmt.Printf("Benz is stop \n")
- }
- func(this * Benz) ChatUp() {
- fmt.Printf("ChatUp \n")
- }
- func main() {
- var car Car fmt.Println(car) // <nil>
- var bmw BMW = BMW {
- Name: "宝马"
- }
- car = &bmw fmt.Println(car.NameGet()) //宝马
- car.Run(1) //BMW is running of num is 1
- car.Stop() //BMW is stop
- benz: =&Benz {
- Name: "大奔"
- }
- car = benz fmt.Println(car.NameGet()) //大奔
- car.Run(2) //Benz is running of num is 2
- car.Stop() //Benz is stop
- //car.ChatUp() //ERROR: car.ChatUp undefined (type Car has no field or method ChatUp)
- }
Interface 嵌套
一个接口可以嵌套在另外的接口。
即需要实现 2 个接口的方法。
- type Car interface {
- NameGet() string
- Run(n int)
- Stop()
- }
- type Used interface {
- Car
- Cheap()
- }
类型断言
类型断言,由于接口是一般类型,不知道具体类型,
如果要转成具体类型,可以采用以下方法进行转换:
- var t int
- var x interface{}
- x = t
- y = x.(int) //转成int
- y, ok = x.(int) //转成int,不报错
栗子一:
- func test(i interface{}) {
- // n := i.(int)
- n, ok := i.(int)
- if !ok {
- fmt.Println("error")
- return
- }
- n += 10
- fmt.Println(n)
- }
- func main() {
- var t1 int
- test(t1)
- }
栗子二:
- switch & type
- type Student struct {
- Name string
- }
- func judgmentType(items...interface {}) {
- for k,
- v: =range items {
- switch v. (type) {
- case string:
- fmt.Printf("string, %d[%v]\n", k, v)
- case bool:
- fmt.Printf("bool, %d[%v]\n", k, v)
- case int,
- int32,
- int64: fmt.Printf("int, %d[%v]\n", k, v)
- case float32,
- float64: fmt.Printf("float, %d[%v]\n", k, v)
- case Student:
- fmt.Printf("Student, %d[%v]\n", k, v)
- case * Student: fmt.Printf("Student, %d[%p]\n", k, v)
- }
- }
- }
- func main() {
- stu1: =&Student {
- Name: "nick"
- }
- judgmentType(1, 2.2, "learing", stu1)
- }
栗子三:
判断一个变量是否实现了指定接口
- type Stringer interface {
- String() string
- }
- type Mystruct interface {
- }
- type Mystruct2 struct {
- }
- func(this * Mystruct2) String() string {
- return ""
- }
- func main() {
- var v Mystruct
- var v2 Mystruct2 v = &v2
- if sv,
- ok: =v. (Stringer);
- ok {
- fmt.Printf("%v implements String(): %s\n", sv.String());
- }
- }
反射 reflect
reflect 包实现了运行时反射,允许程序操作任意类型的对象。
典型用法是用静态类型 interface{} 保存一个值,
通过调用 TypeOf 获取其动态类型信息,该函数返回一个 Type 类型值。
调用 ValueOf 函数返回一个 Value 类型值,该值代表运行时的数据。
func TypeOf(i interface{}) Type
TypeOf 返回接口中保存的值的类型,TypeOf(nil) 会返回 nil。
func ValueOf(i interface{}) Value
ValueOf 返回一个初始化为 i 接口保管的具体值的 Value,ValueOf(nil) 返回 Value 零值。
reflect.Value.Kind
获取变量的类别,返回一个常量
- const (
- Invalid Kind = iota
- Bool
- Int
- Int8
- Int16
- Int32
- Int64
- Uint
- Uint8
- Uint16
- Uint32
- Uint64
- Uintptr
- Float32
- Float64
- Complex64
- Complex128
- Array
- Chan
- Func
- Interface
- Map
- Ptr
- Slice
- String
- Struct
- UnsafePointer
- )
- reflect.Value.Kind()方法返回的常量
reflect.Value.Interface()
转换成 interface{} 类型
【变量 <-->Interface{}<-->Reflect.Value】
获取变量的值:
- reflect.ValueOf(x).Int()
- reflect.ValueOf(x).Float()
- reflect.ValueOf(x).String()
- reflect.ValueOf(x).Bool()
通过反射的来改变变量的值
- reflect.Value.SetXX相关方法,比如:
- reflect.Value.SetInt(),设置整数
- reflect.Value.SetFloat(),设置浮点数
- reflect.Value.SetString(),设置字符串
栗子一
- import "reflect"
- func main() {
- var x float64 = 5.21
- fmt.Println("type:", reflect.TypeOf(x)) //type: float64
- v := reflect.ValueOf(x)
- fmt.Println("value:", v) //value: 5.21
- fmt.Println("type:", v.Type()) //type: float64
- fmt.Println("kind:", v.Kind()) //kind: float64
- fmt.Println("value:", v.Float()) //value: 5.21
- fmt.Println(v.Interface()) //5.21
- fmt.Printf("value is %1.1e\n", v.Interface()) //value is 5.2e+00
- y := v.Interface().(float64)
- fmt.Println(y) //5.21
- }
栗子二(修改值)
SetXX(x) 因为传递的是 x 的值的副本,所以 SetXX 不能够改 x,改动 x 必须向函数传递 x 的指针,SetXX(&x) 。
- //错误代码!!!
- //panic: reflect: reflect.Value.SetFloat using unaddressable value
- func main() {
- var a float64
- fv := reflect.ValueOf(&a)
- fv.SetFloat(520.00)
- fmt.Printf("%v\n", a)
- }
- //正确的,传指针
- func main() {
- var a2 float64
- fv2 := reflect.ValueOf(&a2)
- fv2.Elem().SetFloat(520.00)
- fmt.Printf("%v\n", a2) //520
- }
反射操作结构体
reflect.Value.NumField() 获取结构体中字段的个数
reflect.Value.Method(n).Call(nil) 来调用结构体中的方法
栗子一(通过反射操作结构体)
- import "reflect"
- type NotknownType struct {
- S1 string
- S2 string
- S3 string
- }
- func (n NotknownType) String() string {
- return n.S1 + " & " + n.S2 + " & " + n.S3
- }
- var secret interface{} = NotknownType{"Go", "C", "Python"}
- func main() {
- value := reflect.ValueOf(secret)
- fmt.Println(value) //Go & C & Python
- typ := reflect.TypeOf(secret)
- fmt.Println(typ) //main.NotknownType
- knd := value.Kind()
- fmt.Println(knd) // struct
- for i := 0; i < value.NumField(); i++ {
- fmt.Printf("Field %d: %v\n", i, value.Field(i))
- }
- results := value.Method(0).Call(nil)
- fmt.Println(results) // [Go & C & Python]
- }
栗子二(通过反射修改结构体)
- import "reflect"
- type T struct {
- A int B string
- }
- func main() {
- t: =T {
- 18,
- "nick"
- }
- s: =reflect.ValueOf( & t).Elem() typeOfT: =s.Type()
- for i: =0;
- i < s.NumField();
- i++{
- f: =s.Field(i) fmt.Printf("%d: %s %s = %v\n", i, typeOfT.Field(i).Name, f.Type(), f.Interface())
- }
- s.Field(0).SetInt(25) s.Field(1).SetString("nicky") fmt.Println(t)
- }
- /*
- 输出:
- 0: A int = 18
- 1: B string = nick
- {25 nicky}
- */
- import "reflect"
- type test struct {
- S1 string
- s2 string
- s3 string
- }
- var s interface{} = &test{
- S1: "s1",
- s2: "s2",
- s3: "s3",
- }
- func main() {
- val := reflect.ValueOf(s)
- fmt.Println(val) //&{s1 s2 s3}
- fmt.Println(val.Elem()) //{s1 s2 s3}
- fmt.Println(val.Elem().Field(0)) //s1
- val.Elem().Field(0).SetString("hehe") //S1大写
- }
栗子三(struct tag 内部实现)
- package main
- import (
- "fmt"
- "reflect"
- )
- type User struct {
- Name string `json:"user_name"`
- }
- func main() {
- var user User
- userType := reflect.TypeOf(user)
- jsonString := userType.Field(0).Tag.Get("json")
- fmt.Println(jsonString) //user_name
- }
以上这篇浅谈 Go 语言中的结构体 struct & 接口 Interface & 反射就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持 PHPERZ。
来源: http://www.phperz.com/article/17/0822/344258.html