一文带你玩透结构体和方法

163 阅读5分钟
  1. 结构体的基本定义和使用
package main

import (
   "fmt"
)

//定义结构体类型User
type User struct {
   username string "用户名"
   password string "密码"
   mail     string "邮箱"
}

func main() {
   //初始化方式1
   var user User
   user.username = "ttr"
   user.password = "abc123"
   user.mail = "992424875@qq.com"
   fmt.Println(user)

   //初始化方式2
   user1 := User{"chavis", "1qaz#EDC", "847575@qq.com"}
   fmt.Println(user1)

   //初始化方式3
   user2 := User{username: "root", password: "abc@9089", mail: "root@11.com"}
   fmt.Println(user2)
}
  1. 结构体嵌套
package main

import "fmt"

type Device struct {
   ip        string
   user      string
   pwd       string
   loginType string `登录类型`
}

type Idc struct {
   device Device
   num    int
   addr   string
}

func main() {
   idc := Idc{
      device: Device{ip: "10.1.1.1", user: "root", pwd: "1qaz#EDC", loginType: "ssh"},
      num:    907745,
      addr:   "GZ",
   }
   fmt.Println(idc)
}

输出:

{{10.1.1.1 root 1qaz#EDC ssh} 907745 GZ}
  1. 结构体实例化的3种方式

结构体定义完后是没有分配内存的,需要实例话之后才可以使用结构体。实例化有3种方式:变量定义、new、&符号。

package main

import "fmt"

type Host struct {
   user string
   pwd  string
}

func main() {
   // 变量定义的方式实例化结构体
   var h Host
   h.user = "root"
   h.pwd = "1qaz#EDC"
   fmt.Println(h)

   // new的方式实例化结构体
   var h1 = new(Host)
   h1.user = "admin"
   h1.pwd = "2345#EDC"
   fmt.Println(h1)

   // &符号定义的方式实例化结构体
   var h2 = &Host{}
   h2.user = "ttr"
   h2.pwd = "98768#EDC"
   fmt.Println(h2)
}
  1. 带标签的结构体,标签用于对字段进行说明
package main

import (
   "fmt"
)

type User struct {
   username string "用户名" //"用户名"是标签
   password string "密码"
   mail     string "邮箱"
}

func main() {
   user := User{username: "ttr", password: "1qaz@WSX", mail: "996298929@qq.com"}
   fmt.Println(user)
}
  1. 匿名结构体

匿名结构体不用类型名称,不用使用type关键字定义。

package main

import "fmt"

func main() {
   //基本结构
   user := struct {
   }{}
   fmt.Println(user)

   //定义和初始化
   user1 := struct {
      name string
      age  int
   }{
      "tantianran",
      18,
   }
   fmt.Println(user1)
   fmt.Println(user1.name)
   fmt.Println(user1.age)
}
  1. 给结构体User添加方法show(),该方法输出一个hello
package main

import (
   "fmt"
)

type User struct {
   name string
   age  int
}

func (User) show() {
   fmt.Println("hello")
}

func main() {
   u := User{name: "ttr", age: 17}
   u.show()
}
  1. 给结构体添加方法,并将已经初始化好的值可以在方法内拿到
package main

import (
   "fmt"
)

type User struct {
   name string
   age  int
}

func (u User) show() {
   fmt.Println(u.name, u.age)
}

func main() {
   u := User{name: "ttr", age: 17} //初始化并实例化
   u.show() //调用方法

}

输出:

ttr 17
  1. 给结构体添加方法,并将已经初始化好的值可以在方法内进行修改,注意这里是*User,也就是指针类型
package main

import (
   "fmt"
)

type User struct {
   name string
   age  int
}

func (u *User) chage() {
   u.name = "chavis"
   u.age = 30
}

func main() {
   u := User{name: "ttr", age: 17} //初始化和实例化
   fmt.Println(u.name, u.age)      //修改前
   u.chage()                       //调用chage方法修改已经初始化好的值
   fmt.Println(u.name, u.age)      //修改后
}

输出:

ttr 17
chavis 30

如果不是指针类型,在方法内是无法修改外部已经初始化好的结构体的值,看下面效果

package main

import "fmt"

type User struct {
   name string
   age  int
}

func (u User) chage() {
   u.name = "chavis"
   u.age = 30
}

func main() {
   u := User{name: "ttr", age: 17}
   u.chage()
   fmt.Println(u)
}

输出:

{ttr 17}

看上面的效果可以知道没有被修改成功,因为是值传递,而如果是指针的话,就是直接指向了已经初始化了值且实例化完并赋给变量u所在的那块内存地址。

  1. 在上一个栗子的基础上做改造,使其有返回值,且返回值类型为指针类型
package main

import (
   "fmt"
)

type User struct {
   name string
   age  int
}

func (u *User) chage() *User {
   u.name = "chavis"
   u.age = 30
   return u
}

func main() {
   u := User{name: "ttr", age: 17}
   a := u.chage()
   fmt.Println(*a)
}

输出:

{chavis 30}
  1. 在一个普通的函数内修改外部结构体的值
package main

import "fmt"

type User struct {
   name string
   age  int
}

func chage(data *User) {
   data.name = "tantianran"
   data.age = 30
}

func main() {
   u := &User{name: "ttr", age: 17}
   chage(u)
   fmt.Println(*u)

   //也可以这样
   u1 := User{name: "ttr", age: 17}
   chage(&u1)
   fmt.Println(u1)
}
  1. 任意的类型也都是可以添加方法的,比如给int类型添加一个方法
package main

import "fmt"

type MyInt int

func (x MyInt) check() bool {
   if x > 100 {
      return true
   } else {
      return false
   }
}

func main() {
   a := MyInt(56)
   ret := a.check()
   fmt.Println(ret)
}

输出:

false
  1. 在上一个栗子的基础上,做一个加法,案例1
package main

import "fmt"

type MyInt int

func (x MyInt) add(y MyInt) MyInt {
   return x + y
}

func main() {
   a := MyInt(56)
   ret := a.add(54)
   fmt.Println(ret)
}

输出:

110
  1. 结构体转成json
package main

import (
   "encoding/json"
   "fmt"
)

type Host struct {
   Hostname string
   Ip       string
}

func main() {
   h := Host{
      Hostname: "web01",
      Ip:       "10.1.1.23",
   }
   if jsonStr, err := json.Marshal(h); err != nil {
      fmt.Println(err)
   } else {
      fmt.Println(string(jsonStr))
   }
}

输出:

{"Hostname":"web01","Ip":"10.1.1.23"}

注意:结构体的字段首写字母要大写,否则json包无法读取到字段,进而转换失败(报错),Go语言是通过首字母的大小写来控制访问权限。无论是方法,变量,常量或是自定义的变量类型,如果首字母大写,则可以被外部包访问,反之则不可以。而结构体中的字段名,如果首字母小写的话,则该字段无法被外部包访问和解析。

  1. 刚说到结构体的字段首写字母要大写,如果想转换成json后首字母是小写,可以增加标签来做到,看下面代码
package main

import (
   "encoding/json"
   "fmt"
)

type Host struct {
   Hostname string `json:"hostname"` //标签加在这里
   Ip       string `json:"ip"` //标签加在这里
}

func main() {
   h := Host{
      Hostname: "web01",
      Ip:       "10.1.1.23",
   }
   if jsonStr, err := json.Marshal(h); err != nil {
      fmt.Println(err)
   } else {
      fmt.Println(string(jsonStr))
   }
}

输出:

{"hostname":"web01","ip":"10.1.1.23"}
  1. 将json解析回结构体
package main

import (
   "encoding/json"
   "fmt"
)

type Host struct {
   Hostname string
   Ip       string
}

func main() {
   jsonData := `{"hostname":"web01","ip":"10.1.1.23"}`
   var h Host
   if err := json.Unmarshal([]byte(jsonData), &h); err != nil {
      fmt.Println("Error =", err)
      return
   }
   fmt.Println(h.Hostname)
   fmt.Println(h.Ip)
   fmt.Println(h)
}

输出:

web01
10.1.1.23
{web01 10.1.1.23}

本文装载于:mp.weixin.qq.com/s/g62pZW8h_…