튜토리얼 시리즈를 이동 - 29 연기를

에 오신 것을 환영합니다  튜토리얼 시리즈 Golang 29을.

연기는 무엇입니까?

defer 목적 진술은 : 포함  defer 기능 문을, 그것은 또 다른 함수를 호출, 함수가 반환하기 전에 될 것입니다. 이 정의는 매우 복잡한 것처럼 보일 수 있습니다, 우리는 이해하기 쉬운 예를 사용합니다.

package main

import ( "fmt" ) func finished() { fmt.Println("Finished finding largest") } func largest(nums []int) { defer finished() fmt.Println("Started finding largest") max := nums[0] for _, v := range nums { if v > max { max = v } } fmt.Println("Largest number in", nums, "is", max) } func main() { nums := []int{78, 109, 2, 563, 300} largest(nums) } 

 

위의 절차는 매우 간단합니다, 주어진 조각의 최대 값을 찾는 것입니다. largest int 형의 수신 기능 슬라이스 매개 변수로하고, 상기 프린트 슬라이스의 최대 값. largest function 문을 첫 번째 줄  defer finished(). 이 것을 의미합니다  finished() 함수가 반환하기 전에 호출  finished() 기능. 프로그램을 실행하면 다음과 같은 출력이 표시됩니다 :

Started finding largest  
Largest number in [78 109 2 563 300] is 563 Finished finding largest 

largest 기능이 시작된 후에, 상기 2 줄의 출력을 출력한다. 그리고에서  largest 시간을 반환, 우리는 인쇄, 지연 기능 (이연 기능)를 호출 할  Finished finding largest 텍스트를.:미소:

지연 방법

defer 에 한정되지 않고, 함수 호출의 호출 방법은 합법적이다. 우리는 그것을 테스트 할 수있는 작은 프로그램을 썼다.

package main

import ( "fmt" ) type person struct { firstName string lastName string } func (p person) fullName() { fmt.Printf("%s %s",p.firstName,p.lastName) } func main() { p := person { firstName: "John", lastName: "Smith", } defer p.fullName() fmt.Printf("Welcome ") } 

 

위의 예에서, 우리는 라인 (22)에 대한 메서드 호출을 지연. 코드의 나머지는 여기에 설명되지 않고, 간단합니다. 이 프로그램은 인쇄 :

Welcome John Smith

value 인수 (인수 평가)

이동 언어에서,하지 결정하기 전에 지연 함수 인수를 호출하지만, 실행시  defer 명령문의 시간이이 지연 될 함수 인수가 평가됩니다.

예를 통해 이해할 수있을 것입니다.

package main

import ( "fmt" ) func printA(a int) { fmt.Println("value of a in deferred function", a) } func main() { a := 5 defer printA(a) a = 10 fmt.Println("value of a before deferred function call", a) } 

 

상기 절차에 라인 (11), a (5)의 초기 값. 라인 (12)은 수행  defer 보낸 시간 문  a 동일한 5, 따라서 상기 지연 함수  printA 의 인수도 5와 동일하다. 제 13 행에서, 우리는  a 10의 값으로 수정. 다음 줄은 인쇄 할  a 값을. 이 프로그램은 인쇄 :

value of a before deferred function call 10  
value of a in deferred function 5 

위의 출력에서, 우리는 전화에 그것을 볼 수있는  defer 우리가 되더라도, 문 후  a (10)을 개정,하지만 지연 함수 호출  printA(a), 인쇄는 여전히 5입니다.

연기 栈

함수가 내에서 여러 번 호출 될 때  defer 시간을 이동한다  defer 실행 순서 (최고 우선 아웃, LIFO로) LIFO에 따라 다음 스택에 저장하고 호출한다.

여기에 우리가 사용하는 작은 프로그램 쓰기  defer 역 인쇄 문자열에 스택.

package main

import ( "fmt" ) func main() { name := "Naveen" fmt.Printf("Orignal String: %s\n", string(name)) fmt.Printf("Reversed String: ") for _, v := range []rune(name) { defer fmt.Printf("%c", v) } } 

 

위의 절차에 라인 (11)은 for range 루프는 문자열 라인 (12)의 호출을 반복 할  defer fmt.Printf("%c", v). 이러한 지연은 LIFO의 순서로 수행 호출 스택에 추가되어, 따라서, 문자열은 역으로 인쇄된다. 프로그램 출력됩니다 :

Orignal String: Naveen  
Reversed String: neevaN

의 실용적인 응용 프로그램을 연기

지금까지 우리가 본 코드 샘플은 반영하지 않았다  defer 실제 사용합니다. 이 섹션에서 우리는 볼 것이다  defer 실용적인 응용 프로그램.

함수가 현재 코드 스트림에서 호출 (코드 흐름) 환경의 독립을 할 때 사용할 수 있습니다  defer. 우리는 A를 사용하는  WaitGroup 이 문장의 코드 예제의 의미를 이해 할 수 있습니다. 우리는 먼저 사용하지 않는 쓸 것입니다  defer 우리가 사용하는 프로그램을  defer 보고, 수정  defer 혜택을.

package main

import ( "fmt" "sync" ) type rect struct { length int width int } func (r rect) area(wg *sync.WaitGroup) { if r.length < 0 { fmt.Printf("rect %v's length should be greater than zero\n", r) wg.Done() return } if r.width < 0 { fmt.Printf("rect %v's width should be greater than zero\n", r) wg.Done() return } area := r.length * r.width fmt.Printf("rect %v's area %d\n", r, area) wg.Done() } func main() { var wg sync.WaitGroup r1 := rect{-67, 89} r2 := rect{5, -67} r3 := rect{8, 9} rects := []rect{r1, r2, r3} for _, v := range rects { wg.Add(1) go v.area(&wg) } wg.Wait() fmt.Println("All go routines finished executing") } 

 

상기 절차에서는, 8 라인의 생성  rect 만드는 구조, 및 라인 (13)을  rect 하는 방법  area직사각형의 면적을 계산한다. area 사각형의 길이와 폭이 0보다 작은이 있는지 확인합니다. 직사각형의 길이 및 폭이 0보다 작은 경우, 대응하는 메시지가 출력되며, 제로보다 큰 경우, 직사각형 영역을 출력한다.

main 기능은 세 가지 생성  rect 유형의 r1변수를 : , r2 및  r3. 라인 (34)에, 우리는 이러한 세 가지 변수를 추가  rects 내부 썬다. 섹션은 사용되었다  for range 로 순환  area 동시 이동 코 루틴 호 (37 행)과 같은 방법. 우리는 사용  WaitGroup wg 수 있도록  main 실행 다른 코 루틴 후 함수가 실행이 종료됩니다. WaitGroup 매개 변수로 전달  area 라인 (16), 라인 (21), 라인 (26)에 통지하고, 상기 방법은  main 함수, 지금은 코 루틴 작업이 완료 나타낸다. 당신이 자세히 보면, 당신은 발견 할 것이다  wg.Done() 단지  area 함수가 반환 할 때 호출됩니다. wg.Done() 그것은에서해야  area 호출에 관계없이 경로 (경로) 코드 스트림의 반환, 그리고 수 전에, 그래서 우리는 한 번만 호출 할 수 있습니다  defer효과적으로 대체하기 위해,  wg.Done() 여러 번 호출 .

우리는하는 데 사용  defer 위의 코드를 다시 작성.

다음 코드에서, 우리는 원래의 프로그램 3 제거  wg.Done 전화를하지만, 별도의과  defer wg.Done() (라인 14)을 교체하십시오. 이것은 우리의 코드를보다 간결하고 이해하기 쉽습니다.

package main

import ( "fmt" "sync" ) type rect struct { length int width int } func (r rect) area(wg *sync.WaitGroup) { defer wg.Done() if r.length < 0 { fmt.Printf("rect %v's length should be greater than zero\n", r) return } if r.width < 0 { fmt.Printf("rect %v's width should be greater than zero\n", r) return } area := r.length * r.width fmt.Printf("rect %v's area %d\n", r, area) } func main() { var wg sync.WaitGroup r1 := rect{-67, 89} r2 := rect{5, -67} r3 := rect{8, 9} rects := []rect{r1, r2, r3} for _, v := range rects { wg.Add(1) go v.area(&wg) } wg.Wait() fmt.Println("All go routines finished executing") } 

 

프로그램 출력됩니다 :

rect {8 9}'s area 72  
rect {-67 89}'s length should be greater than zero rect {5 -67}'s width should be greater than zero All go routines finished executing 

상기 과정에서 사용한  defer 또 다른 장점. 우리가 사용하는 가정  if 조건문을, 그리고 준  area 리턴 경로 (반환 경로)를 추가하는 방법을. 사용하지 않는 경우  defer 전화  wg.Done(), 우리는 새로 호출에 추가이의 반환 경로에 다음을 보장하기 위해 매우 조심 있습니다  wg.Done(). 이제 우리는 지연 부르는  wg.Done()이 새로운 복귀 경로에 추가 할 필요가 없습니다  wg.Done() 의는.

이 튜토리얼은 끝났습니다. 나는 당신이 행복 바랍니다.

추천

출처www.cnblogs.com/fengchuiyizh/p/11356112.html