当前位置:网站首页>Functions and pointers in 08 go language

Functions and pointers in 08 go language

2022-07-28 12:29:00 A little boy who loves to write code

function

Go Support function in language 、 Anonymous functions and closures , And the function is in G Language belongs to “ First class citizen ”.

The basic definition of a function

Go In the language, the definition function uses func keyword , The specific format is as follows :

func  Function name ( Parameters )( Return value ){
    
     The body of the function 
}

among :

  • Function name : By letter 、 Numbers 、 Underline composition . But the first letter of a function name cannot be a number . In the same package , Function names can't be duplicated ( The concept of package is described in the following article ).

  • Parameters : Parameters consist of parameter variables and their types , Use... Between multiple parameters , Separate .

  • Return value : The return value consists of the return value variable and its variable type , You can also write only the type of the return value , Multiple return values must use () The parcel , And use , Separate .

  • The body of the function : A block of code that implements a specified function .

    Let's define a function for the sum of two numbers :

    func intSum(x int,y int)int{
          
      return x+y
    }
    

The parameters and return values of the function are optional , For example, we can implement a function that requires neither parameters nor return values :

func sayHello() {
    
	fmt.Println("Hello  Shahe ")
}

Function call

After defining the function , We can go through Function name () Call function in the way of . For example, we call the two functions defined above , The code is as follows :

func main() {
    
	sayHello() // Call function 
	res := initSum(4, 5)
	fmt.Println(res)
}

Be careful , When calling a function with a return value , Its return value is not acceptable .

The parameters of the function

Type abbreviation :

If the adjacent variables in the function parameters have the same type , The type can be omitted , for example :

func initSum(x,y int)int{
    
  return x+y
  
}

In the above code ,intSum Function has two arguments , Both parameters are of type int, Therefore, it can be omitted x The type of , because y There is a description of the type ,x Parameters are also of this type .

Indefinite length parameter :

Variable parameters mean that the number of arguments of a function is not fixed .Go The variable parameter in the language passes after the parameter name ... To mark .

Be careful : Variable parameters are usually used as the last parameter of the function .

// Define variable parameter functions 
func initSum2(x ...int) int {
    
	fmt.Println(x) //x It's a slice 
	sum := 0
	for _, v := range x {
    
		sum += v
	}
	return sum

}

-----------------------------------
// Call the function above :

	res1 := initSum2()
	res2 := initSum2(10)
	res3 := initSum2(10, 20)
	res4 := initSum2(10, 20, 30)
	fmt.Println(res1, res2, res3, res4)

// Running results :
[]
[10]
[10 20]
[10 20 30]
0 10 30 60

When variable parameters are used with fixed functions , Variable function is after fixed function , The sample code is as follows :

// Fixed parameter + Variable parameters 
func initSum3(x int, y ...int) int {
    
	fmt.Println(x, y)
	sum := x
	for _, v := range y {
    
		sum += v
	}
	return sum

}

// Call the above function 
res5 := initSum3(100)
	res6 := initSum3(100, 10)
	res7 := initSum3(100, 10, 20)
	fmt.Println(res5, res6, res7)

// Running results :
100 []
100 [10]
100 [10 20]
100 110 130

Essentially , The variable parameters of a function are implemented by slicing .

Be careful : There are no default parameters !!!

Function return value

Go Through... In language return Keyword output, return value .

Multiple return values :

GO Functions in language support multiple return values , If the function has multiple return values , Must use () Wrap all return values .

// Multiple return values 
func calc(x, y int) (int, int) {
     // Define multiple return values 
	sum := x + y
	sub := x - y
	return sum, sub

}
Name the return value

When defining a function, you can name the return value , And use these variables directly in the function body , Finally through return Keywords return .

// Return value naming 
func calc2(x, y int) (sum, sub int) {
    
	sum = x + y // Because the defined parameters have been declared in the return value , Just use the function body directly 
	sub = x - y
	return sum, sub
}
Return value supplement

When the return value type of one of our functions is slice when ,nil Can be seen as an effective slice, There is no need to show that the returned length is 0 The section of .

func someFunc(x string) []int {
    
	if x == "" {
    
		return nil //  There is no need to return []int{}
	}
	...
}

Function advanced

Scope of variable
  1. Global variables

    A global variable is a variable defined outside a function , It works throughout the program's life cycle . Global variables can be accessed in functions .

    package main
    
    import "fmt"
    
    // Define global variables num
    var num int64 = 10
    
    func testGlobalVar() {
          
    	fmt.Printf("num=%d\n", num) // Functions can access global variables num
    }
    func main() {
          
    	testGlobalVar() //num=10
    }
    
  2. local variable

    There are two kinds of local variables : Variables defined in functions and variables defined in statements .

    Variables defined in functions :

    func testGlobalVar() {
          
    	// Define a function local variable num, Only in this function 
    	num := 10
    	fmt.Printf("num=%d\n", num)
    }
    
    func main() {
          
    	testGlobalVar()
    	fmt.Println(num) // Variables cannot be used at this time num
    }
    

    If local variables and global variables have the same name , Priority access to local variables .

    package main
    
    import "fmt"
    
    // Define global variables num
    var num int64 = 10
    
    func testNum() {
          
    	num := 100
    	fmt.Printf("num=%d\n", num) //  Local variables are preferred in functions 
    }
    func main() {
          
    	testNum() // num=100
    }
    

    Statement to define variables :

    Usually we will be in if conditional ,for loop ,switch This way of defining variables is used in statements .

    // Variables defined by the statement block (if Sentence block )
    func testlocalVar2(x, y int) {
          
    	fmt.Println(x, y) // Function parameters can only take effect in this function 
    	if x > 0 {
          
    		z := 10 // Variable z Only in if The statement block takes effect 
    		fmt.Println(z)
    	}
    	// fmt.Println(z) // Variables cannot be used here z
    }
    
    // call 
    testlocalVar2(10,20)
    // Running results :
    10 20
    10
    
    // Variables defined by the statement block (for Sentence block )
    func testlocalVar3() {
          
    	for i := 0; i < 10; i++ {
          
    		fmt.Println(i) // Variable i Only in the present for Loop statement block takes effect 
    	}
    	//fmt.Println(i)  Variables cannot be used here i
    }
    
    // Call function 
    testlocalVar3()
    
    // Running results :
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    Function type and variable

    1、 Define function types

    We can use type Keyword to define a function type , The specific format is as follows :

    type calculation func(int, int) int
    

    The above statement defines a named calculation The function type of . The function in this function type receives two int Type and has a int Return value of type .

    Simply speaking , Any function that satisfies this condition is calculation Function of type , For example, the following add and sub yes calculation type .

    func add(x,y int)int{
          
      return x+y
    }
    
    func sub(x,y int)int{
          
      return x+y
    }
    

    add and sub Can be assigned to calculation Variable of type

    var c calculation
    c=add
    

    2、 Function type variables

    We can declare a variable of function type and assign a value to it

    //type Function type 
    type calculation func(int, int) int // Declare function types 
    func testType() {
          
    	var c calculation             // Make a statement calculation Variable of type c
    	c = initSum                   // hold initSum Assign a value to c
    	fmt.Printf("type of %T\n", c) // type of c:main.calculation
    	fmt.Println(c(2, 4))          // call initsum function 
    
    	f := initSum                  //  Will function add Assign a value to a variable f
    	fmt.Printf("type of %T\n", f) //type of f: func(int, int) int
    	fmt.Println(c(6, 10))         //  call initsum function 
    
    }
    
    // Running results :
    type of main.calculation
    6
    type of func(int, int) int
    16
    

As long as type The beginning of the keyword is the definition type .

3、 Function signature

  • Function signature --> Function definition ( Statement ) The format of , It has nothing to do with parameter name and return value name

  • Function signature --> The parameters of the function 、 The type and number of return values 、 The order should be the same

func fi(name string, age int) {
    }

func fj(age int, name string) {
    }

type MyFF func(string, int)

func f16() {
    
	var mf MyFF
	mf = fi
	// mf = fj //  Function signatures are inconsistent 
	mf("ddd", 1)
}
Higher order function

Higher order function is divided into two parts: function as parameter and function as return value .

1、 Function as parameter

// Higher order function - Function as parameter 
func add(x, y int) int {
    
	return x + y
}
func calc3(x, y int, op func(int, int) int) int {
     // Pass in a name of op The parameters for 2 individual int, Return value int Function of 
	return op(x, y)
}

// call 
func main() {
    
	ret2 := calc(10, 20, add)
	fmt.Println(ret2) //30
}

// Running results :
30

2、 Function as return value

// Higher order function - Function as return value 
/* 1、 A variable is called inside the function res 2、 The return value is res */

func do(x, y int, s string) (res func(int, int) int) {
    
	switch s {
    
	case "+":
		return add
	case "-":
		return sub
	}
	return res
}

func do1(x, y int, s string) func(int, int) int {
    
	var res func(int, int) int
	switch s {
    
	case "+":
		return add
	case "-":
		return sub
	}
	return res
}
Anonymous functions and immediate execution functions

Function can also be used as return value , But in GO In language, functions cannot be defined inside functions like before , Only anonymous functions can be defined . Anonymous functions are functions without function names , The definition format of anonymous function is :

func( Parameters )( Return value ){
    
     The body of the function 
}

1、 Assigning anonymous functions to variables

// Anonymous functions 
//1、 Assigning anonymous functions to variables 

func f33() func() {
    
	f1 := func() {
    
		fmt.Println(" The wonderful weekend is coming to an end ")
	}
	return f1
}

// call 
f33()()

// Running results :
 The wonderful weekend is coming to an end 

2、 Self executing functions

//2、 Self executing functions : The definition of anonymous function is complete () Direct execution 
func f34() {
    
	func() {
    
		fmt.Println(" Ha ha ha ha ")
	}() // Execute now 
}

// Call function 
f34()

// Running results :
 Ha ha ha ha 
Closure

A closure is an entity composed of a function and its associated reference environment . In short , Closure = function + Citation environment . First let's look at an example :

// Closure 
func addr() func(int) int {
    
	var x int

	// Function variables outside the function are used inside the function x
	f := func(y int) int {
    
		x += y
		return x
	}
	// Return anonymous functions as return values 
	return f
}

// call 
func main(){
    
  f1 := addr()        // call addr function 
	fmt.Println(f1(10)) //10
	fmt.Println(f1(20)) //10+20=30

}

// Running results :
10
30

Advanced closure examples 1:

// Define an accumulator 
// The new value is always used by the returned function 

func addr2(x int) func(int) int {
    
	f := func(y int) int {
    
		x += y
		return x
	}
	return f
	// return func (y int) int { // Another form of writing 
	// x +=y
	// return x
	// }
}

// Call function 
func main(){
    
  f1 := addr2(10)
	fmt.Println(f1(20)) // 30
	fmt.Println(f1(30)) //60
}

// Running results :
30
60

Advanced closure examples 2:

/*  Determine whether a name ends with a specified suffix . */
func makeSuffixFunc(suffix string) func(string) string {
    
	return func(name string) string {
    
		if !strings.HasSuffix(name, suffix) {
    
			return name + suffix
		}
		return name

	}
}

// Call function 
func main(){
    
  jpg := makeSuffixFunc(".jpg")
	txt := makeSuffixFunc(".txt")

	fmt.Println(jpg("test")) // test.jpg
	fmt.Println(txt("test")) //test.txt
}

// Running results :
test.jpg
test.txt

Advanced closure examples 3:

/*  Find two numbers sum and sub */

func calcs(base int) (func(int) int, func(int) int) {
    
	add := func(i int) int {
    
		base += i
		return base
	}

	sub := func(i int) int {
    
		base -= i
		return base
	}
	return add, sub
}

// call 
func main(){
    
  f1, f2 := calcs(10)
	fmt.Println(f1(1), f2(2)) //11 9
	fmt.Println(f1(3), f2(4)) // 12 8
}

// Running results :
11 9
12 8
defer
  • What scene will be used defer
    • Release resources
    • Close file
    • Release the connection
  • defer Execution order of
    • Registered before execution
  • defer Execution time of
    • After the return value assignment , Bottom RET Before the order
  • defer Statement cannot receive a return value defer x := sub(10, 2)
//defer sentence 
func deFer() {
    
	fmt.Println("start")
	defer fmt.Println("1")
	defer fmt.Println("2")
	defer fmt.Println("3")
	fmt.Println("end")
}

// call 
deFer()

// Running results :
start
end
3
2
1

Built in functions

Built in functions Introduce
close It's mainly used to close channel
len To find the length , such as string、array、slice、map、channel
new Used to allocate memory , Mainly used to assign value types , such as int、struct. The return is the pointer
make Used to allocate memory , Mainly used to assign reference types , such as channel、map、slice
append Used to append elements to an array 、slice in
panic and recover For error handling
panic and recover

Go There is currently no exception mechanism in the language , But use panic/recover Mode processing error .panic Can trigger... Anywhere , but recover Only in defer The function called is valid .

func funcA() {
    
	fmt.Println("func A")
}

func funcB() {
    
	panic("panic in B")
}

func funcC() {
    
	fmt.Println("func C")
}
func main() {
    
	funcA()
	funcB()
	funcC()
}

// Running results :
func A
panic: panic in B

goroutine 1 [running]:
main.funB(...)
        /Users/alblue/Documents/ Monkey D Luffy go/day03/ Homework /fun.go:212
main.main()
        /Users/alblue/Documents/ Monkey D Luffy go/day03/ Homework /mian.go:52 +0x66

Program duration funcB In the middle of the war, it caused panic Cause the program to crash , Abnormal exit . At this time, we can pass recover Return the program , Keep going back .

func funA() {
    
	fmt.Println("func A")
}

func funB() {
    
	defer func() {
    
		err := recover()
		// If the program appears panic, adopt recover Come back 
		if err != nil {
    
			fmt.Println("recocer ....")
		}
	}()
	panic("panic in B")
}

func funC() {
    
	fmt.Println("func C")
}
func main() {
    
	funcA()
	funcB()
	funcC()
}
// Running results :
func A
recocer ....
func C

Be careful :

  1. recover() It has to go with defer Use .
  2. defer Be sure to trigger panic Before the statement of .

07- The pointer

Any program data is loaded into memory , There are their addresses in memory , This is the pointer . In order to save an address of data in memory , We need pointer variables .

such as ,“ Never overestimate yourself ” This is my motto , I want to write it into the program , As soon as the program starts, this sentence should be loaded into memory ( Suppose the memory address is 0x123456), I assign this to variables in the program A, Assign memory address to variable B. This is the variable B It's a pointer variable . Through the variable A And variables B Can find my motto .

GO The pointer in the language can't be offset and operated . therefore go Pointer operation in language is very simple , We just need to remember two symbols :&( Address fetch ) and *( According to the address ).

Pointer address and pointer type

Each variable has an address at run time , This address represents the location of the variable in memory .Go Used in language & The character is placed in front of the variable to address the variable .GO Value types in languages (int,float,bool,string,array,struct) All have corresponding pointer types , Such as :*int、*string etc. .

The syntax of de variable pointer is as follows :

ptr := &v    // v The type of T

among :

  • v: The variable representing the address to be taken , The type is T
  • ptr: The variable used to receive the address ,ptr The type is *T, It's called T Pointer type of .* For the pointer .
func poInt(){
    
	a:=10
	b:=&a
	fmt.Printf("a:%d ptr:%p\n",a,&a) //a:10 ptr:0xc000014080
	fmt.Printf("b:%p ptr:%T\n",b,b)  //b:0xc000014080 ptr:*int
	
}

// Running results :
a:10 ptr:0xc000014080
b:0xc000014080 ptr:*int

Let's see b := &a Icon :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-U80ibcgw-1656580370457)(day03.assets/image-20220116184209206.png)]

Just two operations :

  1. Take variables x Memory address of : &x What you get is a pointer
  2. With pointer variables p,*p Find the value according to the memory address

Pointer value

In the use of ordinary variables & The operator takes the address and gets the pointer to the variable , Then you can use... On the pointer * operation , That is, the value of the pointer , The code is as follows .

// Pointer value 
func p1() {
    
	// Pointer value 
	a := 10
	b := &a // Take variables a The address of , Save pointer in b in 
	fmt.Printf("type of b:%T\n", b)
	c := *b // Pointer value ( According to the pointer to the memory value )
	fmt.Printf("type of c:%T\n", c)
	fmt.Printf("value of c:%v\n", c)
}

// Running results :
type of b:*int
type of c:int
value of c:10

summary : Take the address operator & And value operators * It's a pair of complementary operators ,& Take out the address ,* Take the value pointed to by the address .

Variable 、 Pointer address 、 Pointer to the variable 、 Address fetch 、 The relationships and characteristics of values are as follows :

  • Address the variable (&) operation , You can get the pointer variable of this variable .
  • The value of the pointer variable is the pointer address .
  • Take the value of pointer variable (*) operation , You can get the value of the original variable that the pointer variable points to .

Pointer value example :

func modify1(x int) {
    
	x = 100
}

func modify2(x *int) {
    
	*x = 100
}

func main() {
    
	a := 10
	modify1(a)
	fmt.Println(a) // 10
	modify2(&a)
	fmt.Println(a) // 100
}

// Running results :
10
100

new and make

new and make Are used to apply for memory ,new Use less

difference :

  1. new Return pointer type
  2. make It can only be used for slice、map、channel The initialization , The three reference types themselves are returned ;
  3. and new Memory allocation for type , And the value used for the pair is of type zero , The return is a pointer to the type .

Let's start with an example :

func main() {
    
	var a *int
	*a = 100
	fmt.Println(*a)

	var b map[string]int
	b[" Shahenaza "] = 100
	fmt.Println(b)
}

Executing the above code causes panic, Why? ? stay Go For variables of reference type in language , We should not only declare it when we use it , And allocate memory space for it , Otherwise our value can't be stored . The declaration of value type does not need to allocate memory space , Because they have allocated memory space by default at the time of declaration . To allocate memory , Just bring out today's new and make. Go In language new and make It's two built-in functions , Mainly used to allocate memory .

1、new

new Functions are not very common , Use new Function to get a pointer of type , And the corresponding value of the pointer is the zero value of the type . for instance :

//new
func newDemo() {
    
	a := new(int)
	b := new(bool)
	fmt.Printf("%T\n", a) //*int
	fmt.Printf("%T\n", b) //*bool
	fmt.Println(*a)       //0
	fmt.Println(*b)       //false
}

// Running results :
*int
*bool
0
false

In the sample code at the beginning of this section var a *int Just declared a pointer variable a But not initialized , Pointer as a reference type needs to be initialized before it has memory space , You can assign it . The built-in... Should be used as follows new Function pair a After initialization, it can be assigned normally :

func newDemo2() {
    
	var a *int
	a = new(int)
	*a = 10
	fmt.Println(*a)
}

// result :
10

2、make

make It's also used for memory allocation , The difference in new, It is only used for slice、map as well as chan Memory creation , And the types it returns are the three types themselves , Not their pointer type , Because these three types are reference types , So there's no need to return their pointers .make The function signature of the function is as follows :

func make(t Type, size ...IntegerType) Type

make Functions are irreplaceable , We are using slice、map as well as channel When , You need to use make To initialize , Then we can operate them . We have explained this in the last chapter , About channel We'll explain it in detail in the following chapters .

In the example at the beginning of this section var b map[string]int Just declare variables b It's a map Variable of type , It needs to be used like the following example code make After the function initializes , It can be assigned a key value pair :

func main() {
    
	var b map[string]int
	b = make(map[string]int, 10)
	b[" Shahenaza "] = 100
	fmt.Println(b)
}

practice

/*  Do you have 50 Gold coins , It needs to be assigned to the following people :Matthew,Sarah,Augustus,Heidi,Emilie,Peter,Giana,Adriano,Aaron,Elizabeth.  The allocation rules are as follows : a.  Every name contains 1 individual 'e' or 'E' branch 1 Gold coins  b.  Every name contains 1 individual 'i' or 'I' branch 2 Gold coins  c.  Every name contains 1 individual 'o' or 'O' branch 3 Gold coins  d:  Every name contains 1 individual 'u' or 'U' branch 4 Gold coins   Write a program , Calculate how many gold coins each user gets , And how many gold coins are left in the end ?  The program structure is as follows , Please implement  ‘dispatchCoin’  function  */
var (
	coins = 50
	users = []string{
    
		"Matthew", "Sarah", "Augustus", "Heidi", "Emilie", "Peter", "Giana", "Adriano", "Aaron", "Elizabeth",
	}
	distribution = make(map[string]int, len(users))
)

func dispatchCoin() ( int) {
    
	// Count each one user How many gold coins are there 
	for _, v := range users {
    
		for _, s := range v {
    
			switch s {
    
			case 'e', 'E':
				distribution[v] += 1
			case 'i', 'I':
				distribution[v] += 2
			case 'o', 'O':
				distribution[v] += 3
			case 'u', 'U':
				distribution[v] += 4
			}
		}
	}

	// Calculate the remaining gold coins 
	var sum int
	for _, v := range distribution {
    
		sum += v
	}
	
	return 50 - sum

}


func main() {
    
	left := dispatchCoin()
	fmt.Println(" be left over :", left)
}

原网站

版权声明
本文为[A little boy who loves to write code]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/197/202207131051523158.html