[Go programming learning] structure, method, interface

Structure

There is no concept of "class" in the Go language, nor does it support such object-oriented concepts as inheritance. However, the structure and "class" of the Go language are both composite structures, and the combination of structures in the Go language has higher scalability and flexibility than object-oriented.

Structure definition

/*
type typeName struct{
    FieldName FieldType
    FieldName FieldType
    FieldName FieldType
}
*/
type Person struct {
    
    
    Name string
    Age int
}

The type of the fields in the structure can be any type, including function types, interface types, and even the structure type itself. For example, we declare the structure type of a node in a linked list.

type ListNode struct{
    
    
    Val int
    Next *ListNode
}

When declaring the structure, we can also not specify the name of the field, for example, the following:

type Person struct {
    
    
	ID string
	int
}

Fields without a specified name are called anonymous fields

Structure operation

It is recommended to use the initialization method with FieldName during initialization. Fields that are not specified are initialized to the zero value of the type by default. Without explaining FieldName, assign values ​​one by one in the order of type declaration. Once struct adds fields, the entire initialization statement will report an error:

s := new(Person)
a := Person{
    
    "Tom",21}//不推荐
b := Person{
    
    
    Name: "T",
    Age:12,
}

The new function creates a pointer to the structure type. During the creation process, memory is automatically allocated for the structure, and each variable in the structure is assigned a corresponding zero value.

After declaring the structure, you can directly operate the structure as follows.

b.Name = "Y"
b.Age = 30

The structure still follows the visibility rules. If the first letter of the structure field is lowercase, the field cannot be directly accessed in other packages.

Visibility principle:
When identifiers (including constants, variables, types, function names, structure fields, etc.) start with an uppercase letter, such as Group1, then the object using this form of identifier can be externally packaged code Used (the client program needs to import this package first), which is called export (like public in object-oriented languages); if the identifier starts with a lowercase letter, it is not visible outside the package, but they are in the entire package The internals are visible and available (like private in object-oriented languages).

Therefore, after importing an external package, you can and can only access the objects exported in the package.

For anonymous fields, you can use the following methods to operate on them:

p := new(Person)
p.ID = "123"
p.int = 10

Through this example, you can also find that for a structure, each data type can only have one anonymous field.

label

In the Go language, the structure has an optional tag in addition to the name and type of the field. The tagged tag can only be accessed by the reflect package. It is generally used for orm or json data transfer. The following code demonstrates how to The structure is labeled.

type Student struct {
    
    
	Name string `json:"name"`
	Age  int    `json:"age"`
}

You can use the json package that comes with go to convert the declared structure variables into json strings.

func ToJson(s *Student) (string, error) {
    
    
	bytes, err := json.Marshal(s)
	if err != nil {
    
    
		return "", nil
	}
	return string(bytes), nil
}

If the structure is not tagged, the output json string is as follows:

{
    
    "Name":"james","Age":35}

If you tag the structure, the output json string is as follows:

{
    
    "name":"james","age":35}

Embedded structure

As a data type, a structure can also live as an anonymous field. At this time, it is called an embedded structure. In the following code, structure A is embedded in structure B:

type A struct {
    
    
	X, Y int
}

type B struct {
    
    
	A
	Name string
}

The fields defined in A can be conveniently operated under the variables of the structure B by means of the embedded structure.

b := new(B)
b.X = 10
b.Y = 20
b.Name = "james"

What should I do when two fields have the same name (possibly an inherited name)?

  1. The outer name will overwrite the inner name (but the memory space of both are reserved), which provides a way to overload fields or methods;
  2. If the same name appears twice at the same level, if the name is used by the program, an error will be raised (it does not matter if it is not used). There is no way to solve the ambiguity caused by this problem, and the programmer must correct it.

example:

type A struct {
    
    a int}
type B struct {
    
    a, b int}

type C struct {
    
    A; B}
var c C

//此时使用C.a访问是错误的
//编译报错:ambiguous selector

type D struct {
    
    B; b float32}
var d D
//使用d.b没问题,如果想要使用内层的b使用d.B.b


type A struct {
    
    a int}
type B struct {
    
    a, b int}

type E struct {
    
    A; B;a int}
var e E
//此时使用e.a访问会得到e中的a,也就是外层的a

method

Method definition

The method is similar to the function, except that a parameter is added between func and the method name when the method is defined, as shown below:

func (r Receiver)func_name(){
    
    
  // body
}

Where r is called the receiver of the method, such as the following example:

type Person struct {
    
    
	name string
}

func (p Person) GetName() string {
    
    
	return p.name
}

The receiver of the GetName method is the Person structure type, which means that we bind a GetName method to the structure Person, which can be called in the following way.

func main() {
    
    
	p := Person{
    
    
		name:"james",
	}
	fmt.Println(p.GetName())
}

Method receiver

There are two types of receivers for a method: value receivers and pointer receivers. The receiver of GetName above is the value receiver. Then define a pointer receiver for the Person structure:

func (p *Person)SetName(name string){
    
    
	p.name = name
}

The method defined by the value receiver is actually a copy of the value receiver when called, so any operation on the value will not affect the original type variable.

But if you use the pointer receiver, the modification in the method body will affect the original variable, because the pointer is also the address, but the address of the pointer itself. At this time, the copied pointer still points to the original value, so the pointer is received The user operation will also affect the value of the original type variable.

And there is one more special point in the go language. It is also possible to use pointers to call methods defined by value receivers, and vice versa, as shown below:

func main() {
    
    
	p := &Person{
    
    
		name: "james",
	}
	fmt.Println(p.GetName()) //指针调用值接收者定义的方法

  p1 := Person{
    
    
		name: "james",
	}
	p1.SetName("kobe")
	fmt.Println(p1.GetName()) //反之
}

interface

Interface definition

The interface defines a set of methods (method sets), but these methods do not contain (implementation) code: they are not implemented (they are abstract). The interface cannot contain variables either.

type Namer interface {
    
    
    Method1(param_list) return_type
    Method2(param_list) return_type
    ...
}

Namer is an interface type

Implement interface

  • A type does not need to explicitly declare that it implements an interface: the interface is implemented implicitly. Multiple types can implement the same interface

  • The type of an interface (in addition to the interface method) can have other methods

  • One type can implement multiple interfaces

  • The interface type can contain a reference to an instance, the type of the instance implements this interface (the interface is a dynamic type)

package main

import "fmt"

type Shaper interface {
    
    
    Area() float32
}

type Square struct {
    
    
    side float32
}

func (sq *Square) Area() float32 {
    
    
    return sq.side * sq.side
}

func main() {
    
    
    sq1 := new(Square)
    sq1.side = 5

    var areaIntf Shaper
    areaIntf = sq1
    // shorter,without separate declaration:
    // areaIntf := Shaper(sq1)
    // or even:
    // areaIntf := sq1
    fmt.Printf("The square has area: %f\n", areaIntf.Area())
}

If the embedded structure implements a certain interface, does it have any effect on the external structure?

package main

import "fmt"

type Test interface {
    
    
	getX() int
}

type A struct {
    
    
	X int
}
type B struct{
    
    
	A
	X int
}
func (a A) getX() int{
    
    
	return a.X
}
func main() {
    
    
	a := A{
    
    
		X:5,
	}
	b := B{
    
    
		A:a,
		X:10,
	}
	fmt.Println(a.getX())// 5
	fmt.Println(b.getX())// 5
}

If B also implements the interface, it will output 10

Type assertion

Sometimes the parameter passed in by the method may be an interface type, but we have to continue to determine which specific type can be used for the next step. At this time, type assertion is used. Example:

func IsSquare(a Shaper) bool {
    
    
	if v, ok := a.(*Square); ok {
    
    
		fmt.Println(v)
		return true
	}
	return false
}

The above method judges the passed in parameter and judges whether it is a Square type. If it is a Square type, it will be converted to v, and ok is used to indicate whether the assertion is successful.

But if we have to judge a type with many subtypes, it is obviously a bit complicated to write this way, and we can use the following method:

func WhatType(a Shaper) {
    
    
	switch a.(type) {
    
    
	case *Square:
		fmt.Println("Square")
	case *Triangle:
		fmt.Println("Triangle")
	default:
		fmt.Println("error")
	}
}

Empty interface

The empty interface is a special type, because it does not define any methods inside, the empty interface can represent any type. For example, the following operations can be performed:

var any interface{
    
    }

any = 1
fmt.Println(any)

any = "hello"
fmt.Println(any)

any = false
fmt.Println(any)

reference

https://github.com/datawhalechina/go-talent

Getting started with Go

Go language core programming

Guess you like

Origin blog.csdn.net/i0o0iW/article/details/111490056