Go language introduction structure follow up & Pointer

Structure follow up & Pointer

Pointer

Variables and memory addresses

  • Each variable has a memory address, which can be used to operate the corresponding memory
func varMem() {
   var a int32 = 100
   fmt.Printf("addr %p\n",&a)
}

func pointMem() {
   var b int32
   b = 32
   var a *int32
   fmt.Printf("addr of a:%v\ntype of a %T\n",a,a)  //Take the address and type of a
   a = &b
   fmt.Printf("a %d addr:%p\ntype of a:%T\nb %d addr %p\n",*a,&a,a,b,&b)
}

Definition and value of pointer

  • &: Address
  • *: take the value corresponding to the pointer
  • Fully judge the case when the pointer is nil
func pointMem1()  {
   var a *int
   b := 200
   a = &b
   *a = 400
   fmt.Printf("a=%v,adda=%p,type a=%#T\nb=%v,addb=%p,type b=%#T\n",*a,a,a,b,&b)
}
func pointMem2()  {
   var a *int
   var b int = 100
   if a == nil {
      a = &b
   }
   fmt.Printf("addr a=%p,value a=%d\naddr b=%p,value b=%d\n",a,*a,&b,b)
}
  • Small example

Guessing output

func modify(a int) {
   a = 1000
}

func modify2(a *int) {
   fmt.Printf("address of a: %p\n",&a)
   *a = 1000
}

func main() {
   var b int = 100
   modify(b)
   fmt.Printf("b=%d\n",b)
   var p *int = &b
   fmt.Printf("address of p: %p\n",&p)
   modify2(&b)
   fmt.Printf("b=%d\n",b)
}

Pointer variable parameter transfer

  • Modify array
func modifyArray(arr *[3]int) {
   //The modified arr becomes a reference type rather than a value type because its memory address is consistent
   fmt.Printf("2. arr=%#v,address=%p\n",*arr,&arr)
   (*arr)[0] = 90
   fmt.Printf("3. arr=%#v,address=%p\n",*arr,&arr)
}

func main() {
   a := [3]int{89,90,91}
   modifyArray(&a)
   fmt.Printf("1. arr=%#v,addreess=%p\n",a,&a)
}
  • Slice parameters: slice is a reference type, and the bottom layer is a pointer, so it can be modified directly
func modifySlice(a []int) {
   fmt.Printf("2.slice=%v,address=%p\n",a,&a)
   a[0] = 90
   fmt.Printf("3.slice=%v,address=%p\n",a,&a)
}

func main() {
   a := []int{89,90,91}
   modifySlice(a)
   fmt.Printf("1. silce=%#v,address=%p\n",a,&a)
}

Pointer type

  • make is used to allocate reference type memory, such as map, channel, slice
  • new is used to allocate memory of all other types except reference types, such as int, array, etc
func newPoints() {
   var p *int = new(int)
   fmt.Printf("p=%v,address=%p\n",p,&p)
   *p = 100
   fmt.Printf("p=%v,address=%p\n",*p,&p)
}

type User struct {
   Name     string
   Age      int
}

func StructPoint() {
   var pUser *User = new(User)
   pUser.Name = "alex"
   pUser.Age = 19
   fmt.Printf("user:%v\n",*pUser)
}

func newSlice() {
   var p *[]int = new([]int)
   *p = make([]int,10)
   (*p)[0] = 100
   fmt.Printf("p=%v,address=%p\n",*p,&p)
}

func newMap() {
   var p *map[string]int = new(map[string]int)
   *p = make(map[string]int)
   (*p)["key1"] = 100
   (*p)["key2"] = 200
   fmt.Printf("p=%v,address=%p\n",*p,&p)
}

func main() {
   newPoints()
   StructPoint()
   newSlice()
   newMap()
}

Value copy and reference copy

  • Value copy is to re open the memory space of the copy object, and then put the copy value into the new memory space
  • Reference copy is the copy memory address, pointing to the same value
func valueCopy() {
   a := 10
   b := a
   fmt.Printf("a=%d,address a=%p,b=%d,address b=%p\n",a,&a,b,&b)
   c := 10
   d := &c
   fmt.Printf("c=%d,address c=%p,d=%d,address d=%p\n",c,&c,*d,d)
}

object-oriented programming

Method definition

  • Unlike other languages, go is implemented in another way
  • Go's method is to add a receiver in front of the function so that the compiler knows what type the method belongs to
type Students struct {
   Name string
   Age  int
}

//Defines a method whose value type is Students
func (s Students) GetName() string{
   return s.Name
}

//Modify methods that require pointer types
func (s *Students) SetName(name string) {
   s.Name = name
}

func main() {
   var s1 Students  = Students{
      Name:"s1",
      Age:12,
   }
   name := s1.GetName()
   fmt.Printf("name=%s\n",name)

   //Modify name
   s1.SetName("s2")
   name = s1.GetName()
   fmt.Printf("name=%s\n",name)
}
  • You can add methods to any type in the current package
//Define an integer type
type Integer int64

func (i Integer) Print()  {
   fmt.Printf("i=%d\n",i)
}

func (i *Integer) Set(b int64) {
   *i = Integer(b)
}

func main() {
   var a Integer
   a = 1000
   fmt.Printf("a=%d\n",a)
   var b int64 = 500
   a = Integer(b)
   fmt.Printf("a=%d\n",a)
   a.Print()
   a.Set(10000)
   a.Print()
}
  • Function is not of any type, method is of a specific type
  • Pointer type as receiver
  • The difference between value type and pointer type as receiver
    • Pointer type can be modified
    • Value types can only be read-only
    • Generally, the pointer type is regarded as the receiver of reading and writing
//Define an integer type
type Integer int64

func (i *Integer) Print()  {
   fmt.Printf("i=%d\n",*i)
}

func (i *Integer) Set(b int64) {
   *i = Integer(b)
}

func main() {
   var a Integer
   a = 1000
   fmt.Printf("a=%d\n",a)
   var b int64 = 500
   a = Integer(b)
   fmt.Printf("a=%d\n",a)
   a.Print()
   a.Set(10000)
   a.Print()
}

When to use pointer type

  • When you need to change the value in the receiver
  • When the recipient is a large object, the cost of copying copies is relatively high
  • Generally, pointer type is used as receiver
type Users struct {
   s1 [100000000]int64
   s2 [100000000]int64
   s3 [100000000]int64
   s4 [100000000]int64
}

func (u *Users) SetValue() {
   for i :=0;i<len(u.s1);i++ {
      u.s1[i] = 1
      u.s2[i] = 1
      u.s3[i] = 1
      u.s4[i] = 1
   }
}

func main() {
   var u *Users = new(Users)
   start := time.Now().UnixNano()
   u.SetValue()
   end := time.Now().UnixNano()
   fmt.Printf("Total time consumption:%v ms\n",(end-start)/1000000)
}

Method inheritance

  • Structure Inheritance
  • Method inheritance
type Animal struct {
   Name string
   Age  int
}

func (a *Animal) SetName(name string) {
   a.Name = name
}

func (a *Animal) SetAge(age int) {
   a.Age = age
}

func (a *Animal) Print() {
   fmt.Printf("a.name=%s a.age=%d\n",a.Name,a.Age)
}

type Brids struct {
   //Inherit the parent class, use the pointer, and initialize the parent class when initializing
   *Animal
}

func (b *Brids) Fly() {
   fmt.Printf("name %s is flying \n",b.Name)
}

func main() {
   //Inherit the parent class, use the pointer, and initialize the parent class when initializing
   var b *Brids = &Brids{
      &Animal{},
   }
   //Method inherited from parent class
   b.SetName("birds")
   b.SetAge(12)
   //Call your own methods
   b.Fly()
}

Multiple inheritance and conflict resolution

  • Multiple inheritance is not recommended

Structure to JSON (serialization)

type Animal struct {
   Name string
   Age  int
}

func (a *Animal) SetName(name string) {
   a.Name = name
}

func (a *Animal) SetAge(age int) {
   a.Age = age
}

func (a *Animal) Print() {
   fmt.Printf("a.name=%s a.age=%d\n",a.Name,a.Age)
}

type Brids struct {
   //Inherit the parent class, use the pointer, and initialize the parent class when initializing
   *Animal
}

func (b *Brids) Fly() {
   fmt.Printf("name %s is flying \n",b.Name)
}

func main() {
   //Inherit the parent class, use the pointer, and initialize the parent class when initializing
   var b *Brids = &Brids{
      &Animal{},
   }
   //Method inherited from parent class
   b.SetName("birds")
   b.SetAge(12)
   //Call your own methods
   b.Fly()
   // json serialization
   data,err := json.Marshal(b)
   fmt.Printf("marshal result:%s,error :%v\n",data,err)
   //Deserialization: becoming a structure
   var c Brids
   json.Unmarshal(data,&c)
   fmt.Printf("%#v\n",c.Animal)
}

Tags: Go JSON Programming

Posted on Thu, 26 Mar 2020 11:40:35 -0400 by sylesia