Go结构point_struct
point_struct
[toc]
一.struct自整理部分
(一).struct核心基础知识点
1.在一个struct中,字段名字必须唯一。
2.如果字段在代码中从不会用到,可以命名为_(空标识符号)。
3.struct是值类型,使用new(structName)来给该结构体变量分配内存。
它返回指向已分配内存的指针。
type Teacher struct {
name string
age uint8
sex string
}
var t Teacher // t是结构体类型变量
var tp *Teacher // tp是指向一个结构体类型变量的指针
4.结构体初始化方式:
t2 := &Teacher{} // 这种写法依旧会调用new()初始化。
t3 := new(Teacher)
5.带tag的struct
package main
import (
"fmt"
"reflect"
)
type Tag struct {
goodsNumber bool "是否有存货"
goodsName string "商品名称"
goodsPrice int "商品价格"
}
// 这里的标签内容只有reflec可以获取
func getTagFromReflect(TagType Tag,Index int){
getTagType := reflect.TypeOf(TagType)
indexField := getTagType.Field(Index)
fmt.Printf("%v\n",indexField.Tag)
}
func main() {
t := Tag{true, "apple", 130}
for i := 0; i < 3; i++ {
getTagFromReflect(t, i)
}
}
6.在一个struct中每一种数据类型只能有一个匿名字段。
7.案例
// 定义struct实例
type Employee struct {
Id string
Name string
Age int
}
// 实例创建以及初始化
e := Employee{"0", "Bob", 20}
e1 := Employee{Name: "Mike", Age: 30}
e2 := new(Employee) //注意这⾥里里返回的引⽤用/指针,相当于 e := &Employee{}
e2.Id = "2" //与其他主要编程语⾔言的差异:通过实例例的指针访问成员不不需要使⽤用-> e2.Age = 22
e2.Name = "Rose"
// 行为(方法)的定义
//第一种定义⽅方式在实例例对应⽅方法被调⽤用时,实例例的成员会进⾏行行值复制
func (e Employee) String() string {
return fmt.Sprintf("ID:%s-Name:%s-Age:%d", e.Id, e.Name, e.Age)
}
//通常情况下为了了避免内存拷⻉贝我们使⽤用第二种定义⽅方式
func (e *Employee) String() string {
return fmt.Sprintf("ID:%s/Name:%s/Age:%d", e.Id, e.Name, e.Age)
}
8.接口方法结构体应用案例
package jesse_test
import (
"fmt"
"testing"
)
type Car interface {
Run() string
}
type BMW struct {
Name string
}
func (b *BMW) Run() string {
return fmt.Sprintf("我是一辆%v车,我跑的很开心\n", b.Name)
}
type Tesla struct {
Name string
}
func (t *Tesla) Run() string {
return fmt.Sprintf("我是一辆%v车,我跑的很开心\n", t.Name)
}
func AutoRun(c Car) {
fmt.Printf("我的类型是%T,我是:%v\n", c, c.Run())
}
func TestCar(t *testing.T) {
//var i Car
//i = &BMW{"宝马"}
//fmt.Println(i.Run())
//startTime := time.Now()
//测试二
bmwCar := &BMW{"宝马"}
AutoRun(bmwCar)
//teslaCar := new(Tesla)
teslaCar := &Tesla{"Tesla"}
AutoRun(teslaCar)
//time.Sleep(100)
//fmt.Println(time.Since(startTime).Seconds())
}
二.指针
1.指针存取
- a = 10 b=&a // 相当于取存储a的盒子地址。
- &a &b 的类型为指针。
- &的作用为获取变量的地址。
- *int表示变量的类型为整数的指针。
- 指针类型不能做加减。
2.关联案例代码
main.go
#----------------------------------------------------------------------------
package main
import "fmt"
func add(a,b *int){
*a+=*b
}
func put(m map[string]string){
m["a"]="AAA"
}
func main() {
a,b := 1,2
add(&a,&b)
fmt.Println(a)
// a=3,b=2
c := &a // *int c指向a的盒子,*c 取出a里面存的东西3
d := &c // **int d指向c的盒子,d本身也是指针,它存的也是指针。
fmt.Println("d =",d,"*d =",*d,"**d =",**d)
m := map[string]string{}
mp1 := &m // mp1的类型是 *map[string]string
fmt.Println("mp1:",mp1)
put(m)
fmt.Println("第一次put m:",m)
fmt.Println("*mp1=",*mp1)
f1 := add // f1 = func(int,int)
f1(&a,&b)
fmt.Println("第一次打印:",a) // a=5
f2 := &f1
(*f2)(&a,&b)
fmt.Println("第二次打印:",a) // a=7
// 空指针 未初始化为nil
{
var nothing *int
nothing = new(int) // 这里是我完善的。
*nothing = 3
fmt.Println("*nothing", *nothing)
}
// 测试未初始化的map,初始值也是nil
{
var nothing map[string]string = make(map[string]string)
nothing["a"]="mapa"
nothing["a1"]="mapa"
nothing["a2"]="mapa"
nothing["a3"]="mapa"
fmt.Println("空map:",nothing)
}
// 测试空slice
{
var nothingSlice []int
nothingSlice = append(nothingSlice,1)
nothingSlice[0]=100 // 但是这里可以直接append操作
fmt.Println("slice:",nothingSlice)
}
}
#----------------------------------------------------------------------------
三.Go面向对象编程
1.Go语言支持面向对象编程(OOP,Object-orientedprogramming)。虽然Go语言不是严格的面向对象编程语言。
2.Go语言中的结构体(struct)与其它语言中的类(class)在面向对象编程中处于同等地位。
3.Go语言中没有严格的继承、方法重载、构造函数等。
4.Go语言通过接口(interface)完成面向对象编程。
5.对象实战案例
#----------------------------------------------------------------------------
package main
import "fmt"
// 声明一个对象 对象的体现方式为struct
type Person struct {
Name string
Sex string
Tall float64
Weight float64
Age int
}
func inputPeopleInfo() {
// person是一个slice,类型是一个struct
person := []Person{
{
"jesse",
"男",
float64(1.75),
float64(70),
27,
},
{
"jesse1",
"男1",
float64(1.76),
float64(71),
28,
},
}
for _,items := range person{
fmt.Println(items)
}
}
func main() {
inputPeopleInfo()
}
#----------------------------------------------------------------------------
6.为什么要有struct
当一组数据总是围绕着某个主体时,表示这些数据与这个主体之间有紧密的关联关系,可将该主体提
取为一个对象,围绕着主体的数据为这个对象的属性,围绕着这些数据的操作即为该主体的成员函数。
Go 语言中,对象的体现方式为结构体(struct)。
7.怎么定义结构体变量?
var <变量名> [*]<变量类型>
var tom Person
var tom *Person
<变量名> := [&]<变量类型>{}
tom := Person{}
tom := &Person{}
<变量名> := [&]<变量类型>{[ [属性名]:[属性值] ]}
tom := &Person{"Tom”, 23}
tom := &Person{Name: "Tom”, Age: 23}
var <变量名> *<变量类型> = new(Person)
var tom *Person = new(Person)
8.结构体的操作
- 结构体的属性在同一个包内均可见
- 只有公有的结构体、成员变量、成员函数在包外部可见
- 结构体的成员函数执行时,只能通过结构体指针的成员函数进行更改
9.结构体的嵌套
- 结构体的嵌套是指直接嵌入其他结构体完成结构体的定义。
- 被嵌入的结构体的所有成员变量、成员方法都可以直接被使用。
- 注意:
- 被嵌入的结构体的成员变量、成员函数也遵循公有、私有访问限制。
- 在创建变量时,嵌入的对象也需要实例化,尤其是引用类型。如:指针类型、Map。
10.结构体的嵌套实例化一
#----------------------------------------------------------------------------
package calc
type Calculator struct {
Left, Right int
Result int
}
type NewCalculator struct {
old Calculator
}
func getNewCalculator() *NewCalculator {
return &NewCalculator{} //old自动被实例化
}
type NewCalculator2 struct {
old *Calculator
}
func getNewCalculator2() *NewCalculator2 {
return &NewCalculator2{old: &Calculator{}}
//old必须实例化,否则会空指针错误
}
#----------------------------------------------------------------------------
11.结构体的嵌套实例化二
#----------------------------------------------------------------------------
package main
import (
"fmt"
)
type Calculator struct {
Left, Right int
//OP string
Result int
}
// 测试继承
type NewCalculator struct {
Calculator
}
// 测试传入引用类型
type PointCalcularor struct {
old *Calculator
}
// 方法
func (c *Calculator) Add() int {
tmpResult := c.Left + c.Right
c.Result = tmpResult
fmt.Printf("c.result = %v\n",c.Result)
return tmpResult
}
func (c *Calculator) Sub() int {
return c.Left - c.Right
}
func (c *Calculator) Multiple() int {
return c.Left * c.Right
}
func (c *Calculator) Divide() int {
return c.Left / c.Right
}
func (c *Calculator) Remainder() int {
return c.Left % c.Right
}
func calcFunc() {
//fmt.Scanln(&Left)
//fmt.Scanln(&Right)
//fmt.Scanln(&OP)
//switch op {
//case "+":
//case "-":
//case "*":
//case "/":
//case "%":
//default:
// fmt.Println("Not supported calculator rule.")
//}
var c = &Calculator{
Left: 1,
Right: 11,
}
fmt.Println(c.Add())
// 测试继承
newC := &NewCalculator{}
newC.Left = 999
newC.Right = 888
fmt.Println(newC.Add())
//测试继承的是引用类型 嵌入的对象也需要实例化 负责会抛异常。
pointC := &PointCalcularor{old:&Calculator{
Left: 999,
Right: 876,
}}
//pointC.old.Left =200
//pointC.old.Right=1
fmt.Println(pointC.old.Add())
fmt.Println("pointC:",pointC.old.Add())
}
// 结构体里面定义的属性如果是引用类型 需要进行初始化 否则会抛出异常。
type MyCommand struct {
mainCommand *string
commandOptions map[string]string
}
func (m *MyCommand) ToCmdStr() string {
out := ""
for k,v := range m.commandOptions{
out = out + fmt.Sprintf("--%s=%s",k,v)
}
return out
}
func testCmd(){
mc := &MyCommand{
new(string),
make(map[string]string),
}
mc.commandOptions["author"]="jesse"
*mc.mainCommand="myPointType"
fmt.Println(*mc.mainCommand)
fmt.Println(mc.ToCmdStr())
}
func main() {
//calcFunc()
testCmd()
}
#----------------------------------------------------------------------------
12.sort.Slice测试案例
main.go
#----------------------------------------------------------------------------
package main
import (
"fmt"
"sort"
)
type Peopel struct {
Name string
Age int
}
func InitPeople()(arrs []Peopel){
//arr1 :=Peopel{
// Name: "jesse",
// Age: 23,
//}
//arr2 :=Peopel{
// Name: "maggie",
// Age: 24,
//}
//arr3 :=Peopel{
// Name: "gina",
// Age: 25,
//}
//arr4 :=Peopel{
// Name: "jack",
// Age: 26,
//}
//
//arrs = append(arrs,arr1,arr2,arr3,arr4)
//return arrs
arrs = []Peopel{
{
"jesse",
23,
},
{
"maggie",
21,
},
{
"gina",
29,
},
{
"rainbow",
31,
},
}
return
}
func main(){
arrs := InitPeople()
fmt.Println("before:",arrs)
sort.Slice(arrs, func(i, j int) bool {
// 从小到大排列
return arrs[i].Age < arrs[j].Age
})
fmt.Println("按照年龄 从小到大排列:",arrs)
#----------------------------------------------------------------------------
四.面向对象的特殊类型
1.prometheus的一个核心引擎的接口定义.
- https://github.com/prometheus/prometheus/blob/main/promql/engine.go
2.类型重命名
- 为已有的类型创建一个新的别名,从而在不更改类型的情况下提高类型的辨识度。
- type 新名称 = 要命名的名称/ type Math = int
3.投票小游戏
- 班里100个人,现在我们选出1个班长,一个副班长。
- 每个人有两张票,一张赞成票,一张反对票,每个人根据自己对其他99个人的了解来头哦票。
- 得赞成票最多的是班长,赞成票第二多的是副班长,如果赞成票相同,得反对票少的当选。
#----------------------------------------------------------------------------
package main
import (
"fmt"
"math/rand"
"time"
)
type Math = int
type English = int
type Chinese = int
func getScoreOfStudent(name string) (Math, Chinese, English) {
//todo
return 1, 2, 3
}
func callGetScoreOfStudent() {
var mathScore int = 100
var mathScore2 Math = 101
mathScore = mathScore2
fmt.Println(mathScore)
math, chinese, english := getScoreOfStudent("jesse")
fmt.Printf("math:%v,chinese:%v,english:%v\n", math, chinese, english)
}
// 投票小游戏
type VoteGame struct {
students []*Student
}
func (v *VoteGame)goRun()(leader *Student) {
for _,item :=range v.students{
rand.Seed(time.Now().UnixNano())
randInt := rand.Int()
if randInt %2 ==0 {
item.voteA(v.students[randInt%len(v.students)]) // todo 使用随机数代替
}else {
item.voteA(v.students[randInt%len(v.students)])
}
}
maxScore := -1
maxScoreIndex := -1
for i,item := range v.students{
if maxScore < item.agree{
maxScore = item.agree
maxScoreIndex = i
}
}
if maxScoreIndex >=0 { // 判断是否大于0,如果没有学生,那么index就是默认值-1.
return v.students[maxScoreIndex]
}
return nil
}
type Student struct {
name string
agree int
disagree int
}
func (std *Student) voteA(target *Student) {
target.agree++
}
func (std *Student) voteD(target *Student) {
target.disagree++
}
func main() {
vg := &VoteGame{students: []*Student{
&Student{name:fmt.Sprintf("%d",1)},
&Student{name:fmt.Sprintf("%d",2)},
&Student{name:fmt.Sprintf("%d",3)},
&Student{name:fmt.Sprintf("%d",4)},
&Student{name:fmt.Sprintf("%d",5)},
}}
leader := vg.goRun()
fmt.Println(leader)
}
#----------------------------------------------------------------------------
4.对象重定义
- 对象重定义是将对象作为新的对象存在。新对象可以有单独的成员函数以支持不同的操作,或实
现不同的接口。原对象与新对象之间可以无缝转换,但不能直接混用。
语法:
type <新对象类型名称> [*]<原对象类型名称> 例如:
type ClassPresident Person
type Name string
type ConvInt int本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 悩姜!


