目录
别名定义
示例:变量别名定义
package main
import "fmt”
type integer int
func main(){
//类型别名定义
var i integer=1000
fmt.Printin(i)
var j int = 100
//但是属于不同类型,需要做强转
j = int(i)
fmt.Println(j)
}
运行结果
1000
1000
示例:结构体别名定义
package main
import "fmt"
type student struct {
Number int
)
//结构体别名
type stu student
func main(){
var a Student
a = Student{30}
var b Stu
b = Stu{300}
//强转类型
a = Student(b)
fmt.Println(a)
}
运行结果
{300}
工厂模式
创建构造体时初始化构造体,即对构造体属性变量赋初始值。在Go中没有构造函数,可以使用工厂模式来解决。
示例:
package main
import "fmt"
type student struct {
Name string
Age int
}
func main(){
stu1 :=new(Student)
stu2 := NewStudent("zhangsan",20)
fmt.Println(stu1)
fmt.Println(stu2)
}
//工厂模式
func NewStudent(name string,age int) *Student {
return &student{
Name: name,
Age:age,
}
}
运行结果
&{ 0}
&{zhangsan 20}
强调:
1: make用来创建map.slice、channel"
2: new用来创建值类型
Tag原信息
结构体与JSON序列化
跟其他语言进行对接交互时使用JSON格式,有些语言格式有规范大小写严格,为了使Go能和其他语言对接数据传输,故使用Tag原信息来解决。
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。JSON键值对是用来保存JS对象的一种方式,键/值对组合中的键名写在前面并用双引号""包裹,使用冒号:分隔,然后紧接着值;多个键值之间使用英文,分隔。
示例
package main
import(
"encoding/json"
"fmt"
)
type Student struct {
Name string
Age int
Score float32
}
func main() {
var stu Student = Student{
Name: "stu1",
Age: 18,
Score: 80,
}
//使用json格式返回字节数组
data,err := json.Marshal(stu)
if err != nil {
fmt. Println("json encode stu failed,err:", err)
return
}
fmt.Println(data)//字节数组形式输出
fmt. Println(string(data)) //转换成字符串输出
}
运行结果
[123 34 78 97 109 101 34 58 34 115 116 117 49 34 44 34 65 103 101 34 58 49 56 125]
{"Name":"stu1","Age":18}
结构体标签(Tag)
Tag是结构体的元信息,可以在运行的时候通过反射的机制读取出来。
Tag在结构体字段的后方定义,由一对反引号包裹起来,具体的格式如下:
`key1:"value1" key2:"value2"`
结构体标签由一个或多个键值对组成。键与值使用冒号分隔,值用双引号括起来。键值对之间使用一个空格分隔。 注意事项: 为结构体编写Tag时,必须严格遵守键值对的规则。结构体标签的解析代码的容错能力很差,一旦格式写错,编译和运行时都不会提示任何错误,通过反射也无法正确取值。例如不要在key和value之间添加空格。
示例:JSON格式字段名
package main
import (
"encoding/json"
"fmt"
)
type Student struct {
//json打包时字段名
Name string `json:"name"`
Age int `json:"age"`
Score float32 `json:"score"`
}
func main() {
var stu Student = Student{
Name: "stu1",
Age: 18,
Score: 80,
}
//使用json格式返回字节数组
data, err := json.Marshal(stu)
if err != nil {
fmt.Println("json encode stu failed , err: ", err)
return
}
fmt.Println(data)
fmt.Println(string(data))
}
运行结果
[123 34 110 97 109 101 34 58 34 115 116 117 49 34 44 34 97 103 101 34 58 49 56 44 34 115 99 111 114 101 34 58 56 48 125]
{"name":"stu1","age":18,"score":80}
Golang匿名字段 :
可以像字段成员那样访问匿名字段方法,编译器负责查找。
package main
import "fmt"
type User struct {
id int
name string
}
type Manager struct {
User
}
func (self *User) ToString() string { // receiver = &(Manager.User)
return fmt.Sprintf("User: %p, %v", self, self)
}
func main() {
m := Manager{User{1, "Tom"}}
fmt.Printf("Manager: %p\n", &m)
fmt.Println(m.ToString())
}
输出结果:
Manager: 0xc42000a060
User: 0xc42000a060, &{1 Tom}
通过匿名字段,可获得和继承类似的复用能力。依据编译器查找次序,只需在外层定义同名方法,就可以实现 "override"。
package main
import "fmt"
type User struct {
id int
name string
}
type Manager struct {
User
title string
}
func (self *User) ToString() string {
return fmt.Sprintf("User: %p, %v", self, self)
}
func (self *Manager) ToString() string {
return fmt.Sprintf("Manager: %p, %v", self, self)
}
func main() {
m := Manager{User{1, "Tom"}, "Administrator"}
fmt.Println(m.ToString())
fmt.Println(m.User.ToString())
}
输出结果:
Manager: 0xc420074180, &{{1 Tom} Administrator}
User: 0xc420074180, &{1 Tom}
方法
Go中的方法是作用在特定类型的变量上,因此自定义类型,都可以有方法,而不仅仅是struct.
方法定义
func (recevier type) methodName(参数列表)(返回值列表){}
参数和返回值可以省略
• 只能为当前包内命名类型定义方法。
• 参数 receiver 可任意命名。如方法中未曾使用 ,可省略参数名。
• 参数 receiver 类型可以是 T 或 *T。基类型 T 不能是接口或指针。
• 不支持方法重载,receiver 只是参数签名的组成部分。
• 可用实例 value 或 pointer 调用全部方法,编译器自动转换。
一个方法就是一个包含了接受者的函数,接受者可以是命名类型或者结构体类型的一个值或者是一个指针。所有给定类型的方法属于该类型的方法集。
package main
import (
"fmt"
)
//结构体
type User struct {
Name string
Email string
}
//方法
func (u User) Notify() {
fmt.Printf("%v : %v \n", u.Name, u.Email)
}
func main() {
// 值类型调用方法
u1 := User{"golang", "golang@golang.com"}
u1.Notify()
// 指针类型调用方法
u2 := User{"go", "go@go.com"}
u3 := &u2
u3.Notify()
}
输出结果:
golang : golang@golang.com
go : go@go.com
解释: 首先我们定义了一个叫做 User 的结构体类型,然后定义了一个该类型的方法叫做 Notify,该方法的接受者是一个 User 类型的值。要调用 Notify 方法我们需要一个 User 类型的值或者指针。
在这个例子中当我们使用指针时,Go 调整和解引用指针使得调用可以被执行。注意,当接受者不是一个指针时,该方法操作对应接受者的值的副本(意思就是即使你使用了指针调用函数,但是函数的接受者是值类型,所以函数内部操作还是对副本的操作,而不是指针操作。
我们修改 Notify 方法,让它的接受者使用指针类型:
package main
import (
"fmt"
)
//结构体
type User struct {
Name string
Email string
}
//方法
func (u *User) Notify() {
fmt.Printf("%v : %v \n", u.Name, u.Email)
}
func main() {
// 值类型调用方法
u1 := User{"golang", "golang@golang.com"}
u1.Notify()
// 指针类型调用方法
u2 := User{"go", "go@go.com"}
u3 := &u2
u3.Notify()
}
输出结果:
golang : golang@golang.com
go : go@go.com
注意:当接受者是指针时,即使用值类型调用那么函数内部也是对指针的操作。
方法不过是一种特殊的函数,只需将其还原,就知道 receiver T 和 *T 的差别。
package main
import "fmt"
type Data struct {
x int
}
func (self Data) ValueTest() { // func ValueTest(self Data);
fmt.Printf("Value: %p\n", &self)
}
func (self *Data) PointerTest() { // func PointerTest(self *Data);
fmt.Printf("Pointer: %p\n", self)
}
func main() {
d := Data{}
p := &d
fmt.Printf("Data: %p\n", p)
d.ValueTest() // ValueTest(d)
d.PointerTest() // PointerTest(&d)
p.ValueTest() // ValueTest(*p)
p.PointerTest() // PointerTest(p)
}
输出:
Data: 0xc42007c008
Value: 0xc42007c018
Pointer: 0xc42007c008
Value: 0xc42007c020
Pointer: 0xc42007c008
demo
package main
import "fmt"
type Car struct {
Name string
Color string
}
type Bike struct {
Car
wheel float32
}
type Triat struct {
Car
weight int16
}
func (c Car) Run() {
fmt.Println("运行中")
}
func main() {
var bike Bike
bike.Name = "九二"
bike.Color = "red"
bike.wheel = 2
fmt.Println(bike)
bike.Run()
var t Triat
t.Name = "AudiRs 7"
t.Color = "black"
t.weight = 10000
fmt.Println(t)
t.Run()
}
运行结果
{{九二 red} 2}
运行中
{{AudiRs 7 black} 10000}
运行中
示例:传统数据类型自定义方法,做数据类型转化。
package main
import "fmt"
type integer int
//传统数据类型自定义方法
func (p integer) convert() string {
return fmt.Sprintf("%d",p)
}
func main(){
var i integer
i = 100
s := i.convert()
fmt.Printf("类型:%T,值:%s\n", s,s)
}
运行结果
类型:string 值:100
值类型和引用类型
package main
import "fmt"
type integer int
//传统数据类型自定义方法
func (p integer) convert() string {
return fmt.Sprintf("%d", p)
}
//使用指针数据同步修改
func (p *integer) set(b integer) {
*p = b
}
func main() {
var i integer = 100
s := i.convert()
fmt.Printf("类型:%T,值:%s\n", s, s)
fmt.Printf("类型:%T,值: %d\n", i, i)
i.set(200)
fmt.Println(i)
}
运行结果
类型:string,值:100
类型:main.integer,值: 100
200