golang基础(2)

简介: golang基础

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(),

说明

  1. reflect.TypeOf: 直接给到了我们想要的type类型,如float64、int、各种pointer、struct 等等真实的类型
  2. reflect.ValueOf:直接给到了我们想要的具体的值,如1.2345这个具体数值,或者类似&{1 “Allen.Wu” 25} 这样的结构体struct的值
  3. 也就是说明反射可以将“接口类型变量”转换为“反射类型对象”,反射类型指的是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

相关文章
|
10月前
|
Java 编译器 Go
104.【GoLang基础】(二)
104.【GoLang基础】
39 0
|
10月前
|
缓存 并行计算 Go
104.【GoLang基础】(四)
104.【GoLang基础】
39 0
|
10月前
|
编译器 Go Windows
104.【GoLang基础】(一)
104.【GoLang基础】
37 0
|
10月前
|
存储 编译器 Go
104.【GoLang基础】(七)
104.【GoLang基础】
46 0
|
10月前
|
大数据 编译器 Go
104.【GoLang基础】(三)
104.【GoLang基础】
68 0
|
26天前
|
监控 安全 Go
|
26天前
|
Go
|
26天前
|
存储 Java Go
|
26天前
|
存储 JSON 数据库连接
|
8月前
|
中间件 Go API