에 오신 것을 환영합니다 튜토리얼 시리즈 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()
의는.
이 튜토리얼은 끝났습니다. 나는 당신이 행복 바랍니다.