Go 언어 학습 23 오류 처리 및 실행 중 패닉(Panic)
32029 단어 go
한 가지 실수
1.1 오류 유형
약정에 따라 Go의 오류 유형은 error
입니다. 이것은 내장 인터페이스입니다. nil
값은 오류가 없음을 나타냅니다.type error interface {
Error() string
}
오류 유형을 쉽게 사용자 정의할 수 있습니다.package main
import (
"fmt"
)
func main() {
e := MyError{"This is a custom Error Type."}
fmt.Println(e.Error())
v1, err := divide(10, 2)
if err == nil {
fmt.Println(v1)
}
if v2, err := divide(5, 0); err != nil {
fmt.Println(err)
} else {
fmt.Println(v2)
}
}
//
type MyError struct {
msg string
}
func (e *MyError) Error() string {
return e.msg
}
//
func divide(a1, a2 int) (int, error) {
if a2 == 0 {
return 0, &MyError{" , "}
}
return a1 / a2, nil
}
상기divide
함수는 error
값을 되돌려줍니다. 호출자는 이 오류 값에 따라 결과를 어떻게 처리하는지 판단할 수 있습니다.이런 용법은 Go에서 일종의 관용법이다. 특히 함수 라이브러리와 같은 기능을 작성할 때.예를 들어 표준 라이브러리os
의 파일 열기Open
함수는 다음과 같이 정의됩니다.// Open opens the named file for reading. If successful, methods on
// the returned file can be used for reading; the associated file
// descriptor has mode O_RDONLY.
// If there is an error, it will be of type *PathError.
func Open(name string) (*File, error) {
return OpenFile(name, O_RDONLY, 0)
}
함수가 반환하는 구체적인 오류 유형은 PathError
입니다.// PathError records an error and the operation and file path that caused it.
type PathError struct {
Op string
Path string
Err error
}
func (e *PathError) Error() string { return e.Op + " " + e.Path + ": " + e.Err.Error() }
이 오류는 오류를 일으키는 작업과 관련 파일 경로, 오류 설명 정보를 상세하게 설명합니다.
1.2 기타 오류 유형
이외에도 표준 라이브러리에는 직간접적으로 error
인터페이스를 실현하거나 내장한 다른 미리 정의된 오류 유형이 많이 있습니다.예:runtime.Error // Error
net.Error // Error
go/types.Error // Error
html/template.Error // html ( )
os/exec // ( )
또한 표준 라이브러리의 errors
패키지는 error
실례를 쉽게 되돌릴 수 있는 함수를 제공합니다.// New
func New(text string) error
구체적인 구현은 다음과 같습니다.// errors
package errors
// New
func New(text string) error {
return &errorString{text}
}
// errorString error ( )
type errorString struct {
s string
}
func (e *errorString) Error() string {
return e.s
}
예:package main
import (
"errors"
"fmt"
)
func main() {
fmt.Println(errors.New(" "))
}
위의 오류 설명이 너무 간단하면 fmt
패키지의 Errorf
함수를 사용할 수 있습니다.// Errorf , error
func Errorf(format string, a ...interface{}) error {
return errors.New(Sprintf(format, a...))
}
이 함수는 소프트웨어 패키지의 포맷 기능을 사용하여 설명 오류 메시지를 만들 수 있도록 합니다.package main
import (
"fmt"
)
func main() {
const name, id = "bimmler", 17
err := fmt.Errorf("user %q (id %d) not found", name, id)
if err != nil {
fmt.Print(err)
}
}
일반적으로 상기 두 가지 방법은 절대 다수의 잘못된 장면을 만족시킬 수 있다.만약 여전히 부족하다면, 본문에서 말한 바와 같이, 당신은 임의의 오류 유형을 사용자 정의할 수 있습니다.
2 Panic(공황)
내장 함수panic
는 실행 중 오류가 발생할 수 있으며, 이 함수를 호출하면 현재goroutine
는 정상적인 실행 절차를 정지합니다.이런 상황은 일반적으로 일부 중요한 매개 변수가 부족한 검사를 할 때 발생한다. 만약에 이 매개 변수가 부족하면 프로그램이 정상적으로 운행하지 못하게 하기 때문에 프로그램을 계속 운행하게 하는 것보다 (근본적으로 정상적으로 운행할 수 없을 수도 있다) 제때에 중지하게 하는 것이 낫다.func panic(v interface{})
이 함수는 임의의 형식의 실참 (일반적으로 문자열) 을 받아들여 프로그램이 끝날 때 인쇄합니다.package main
func main() {
panic(" 。")
}
다른 유형에서는 장면을 사용합니다.package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("wait for init...")
}
var user = os.Getenv("USER")
func init() {
//
if user == "" {
panic("no value for $USER")
}
}
일반적인 상황에서 우리는panic, 특히 라이브러리 함수에서 사용하는 것을 피해야 한다.panic
가 호출된 후 (명확하지 않은 실행 중 오류, 예를 들어 수조나 절편 인덱스 월, 유형 단언 실패) 등은 현재 함수의 실행을 즉시 중지하고 goroutine
창고를 거슬러 올라가 지연된 함수를 실행합니다.goroutine
창고의 맨 위에 거슬러 올라가면 프로그램이 종료됩니다.
가령 함수F
가 호출되었다고 가정하면panic
의 정상적인 실행은 즉시 중단됩니다.F
중 지연된 함수는 순서대로 실행되고 F
호출처로 되돌아옵니다.호출자F
에 대해서도 이 때 G
함수를 호출하는 것처럼 실행을 멈추고 panic
지연된 모든 함수를 거슬러 올라가기 시작합니다.이 G
의 모든 함수가 멈출 때까지 계속 거슬러 올라가면 프로그램이 종료되고 오류 정보를 보고합니다. goroutine
에게 전달된 매개 변수를 포함합니다.
물론 우리는 내장함수panic
를 사용하여 복구하고 recover
의 제어권을 되찾아 계속 아래를 볼 수 있다.
우리는 defer 문장 한 문장에서 goroutine
창고는 defer
순서로 집행된다고 언급한 적이 있다.
3 Recover(복구)
내장 함수LIFO
는 발생recover
한panicking
을 정상적으로 운행할 수 있다.지연된 함수에서 실행goroutine
하면 recover
의 발생을 중지할 수 있습니다.주의는 지연된 함수에 직접 있어야 합니다.지연 함수에서 (또는 간접적으로) 이 함수를 호출하지 않으면 아무런 작용도 일어나지 않고 panic
되돌아옵니다.프로그램이 발생하지 않았거나 nil
의 매개 변수가 panic
이면 panic
의 반환값도 nil
입니다.func recover() interface{}
다음 예제에서는 panic과 recover의 작업 메커니즘을 보여 줍니다.package main
import "fmt"
func main() {
f()
fmt.Println(" f() 。")
}
func f() {
defer func() {
if r := recover(); r != nil {
fmt.Println(" f() 。", r)
}
}()
fmt.Println(" g()。。。")
g(0)
fmt.Println(" g() 。")
}
func g(i int) {
if i > 3 {
fmt.Println("Panicking!")
panic(fmt.Sprintf("%v", i))
}
defer fmt.Println(" g() ", i)
fmt.Println(" g() ", i)
g(i + 1)
}
func h() {
fmt.Println("hello")
}
effective_ 보기go의 예:
서버에서 실패 recover
를 종료하고 다른 실행 중인 nil
을 죽일 필요가 없습니다.func server(workChan chan *Work) {
for work := range workChan {
go safelyDo(work)
}
}
func safelyDo(work *Work) {
defer func() {
if err := recover(); err != nil {
log.Println("work failed:", err)
}
}()
do(work)
}
복구 모드를 적절하게 사용하면 goroutine
함수(및 호출된 모든 코드)는 호출goroutine
을 통해 더 나쁜 결과를 피할 수 있다.우리는 이런 사상을 이용하여 복잡한 소프트웨어 중의 오류 처리를 간소화할 수 있다.do
패키지의 이상적인 버전을 보면 국부적인 오류 유형 호출 panic
으로 오류를 보고합니다.다음은 regexp
유형, panic
방법 및 Error
함수의 정의입니다.// Error , error 。
type Error string
func (e Error) Error() string {
return string(e)
}
// error *Regexp , Error Panic 。
func (regexp *Regexp) error(err string) {
panic(Error(err))
}
// Compile 。
func Compile(str string) (regexp *Regexp, err error) {
regexp = new(Regexp)
// ,doParse panic
defer func() {
if e := recover(); e != nil {
regexp = nil //
err = e.(Error) // , Panic。
}
}()
return regexp.doParse(str), nil
}
error
트리거된 경우 Compile
복구 블록은 반환 값을 doParse
로 설정합니다. 지연된 함수는 이름이 지정된 반환 값을 수정할 수 있습니다.panic
의 값을 부여하는 과정에서 우리는 그것이 국부적인 유형nil
을 가지고 있는지 단언함으로써 그것을 검사할 것이다.만약 그것이 없다면, 형식 단언은 실패할 것입니다. 실행 중 오류가 발생하고, 모든 것이 중단된 적이 없는 것처럼 창고의 거슬러 올라갑니다.이 검사는 색인 경계선 넘기 같은 의외의 사고가 발생하면 우리가 err
과 Error
을 사용하여 해석 오류를 처리하더라도 코드는 실패할 수 있음을 의미한다.
적절한 오류 처리를 통해 panic
방법(구체적인 유형에 귀속되는 방법이기 때문에 내장된 recover
유형과 이름이 같아도 상관없음)은 보고 오류를 쉽게 처리할 수 있고 거슬러 올라가는 해석 창고를 수동으로 처리할 염려가 없다.if pos == 0 {
re.error("'*' illegal at start of expression")
}
비록 이런 모델은 매우 유용하지만, 그것은 반드시 가방 안에서만 사용해야 한다.error
내부의 error
호출을 Parse
값으로 바꾸고 호출자에게 노출되지 않습니다.이것은 준수할 만한 좋은 규칙이다.
또 이런 재촉발panic
의 관용법은 실제 오류가 발생할 때error
의 값을 바꾼다.그러나 원시적이든 새로운 오류든 붕괴 보고서에 나타나기 때문에 문제의 근원은 여전히 볼 수 있다.이런 간단한 재촉발 panic
모델은 이미 충분하다. 왜냐하면 그것은 단지 붕괴일 뿐이다.그러나 원본 값만 표시하고 싶다면 코드를 많이 써서 필요하지 않은 문제를 필터한 다음 원본 값으로 다시 터치할 수도 있다panic
.
참조:https://golang.org/doc/effective_go.html#errors https://golang.org/pkg/builtin/#error https://blog.golang.org/defer-panic-and-recover
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Go Fiber 및 PlanetScale로 REST API 구축 - 4부
다시 사용자 핸들러에 UpdateUser라는 새 함수를 추가합니다.
업데이트 사용자를 main.go에 등록
이제 응용 프로그램을 다시 실행하십시오.
이전에 생성한 사용자를 업데이트합니다.
응답
사용자가 존재하지 않을...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.
type error interface {
Error() string
}
package main
import (
"fmt"
)
func main() {
e := MyError{"This is a custom Error Type."}
fmt.Println(e.Error())
v1, err := divide(10, 2)
if err == nil {
fmt.Println(v1)
}
if v2, err := divide(5, 0); err != nil {
fmt.Println(err)
} else {
fmt.Println(v2)
}
}
//
type MyError struct {
msg string
}
func (e *MyError) Error() string {
return e.msg
}
//
func divide(a1, a2 int) (int, error) {
if a2 == 0 {
return 0, &MyError{" , "}
}
return a1 / a2, nil
}
// Open opens the named file for reading. If successful, methods on
// the returned file can be used for reading; the associated file
// descriptor has mode O_RDONLY.
// If there is an error, it will be of type *PathError.
func Open(name string) (*File, error) {
return OpenFile(name, O_RDONLY, 0)
}
// PathError records an error and the operation and file path that caused it.
type PathError struct {
Op string
Path string
Err error
}
func (e *PathError) Error() string { return e.Op + " " + e.Path + ": " + e.Err.Error() }
runtime.Error // Error
net.Error // Error
go/types.Error // Error
html/template.Error // html ( )
os/exec // ( )
// New
func New(text string) error
// errors
package errors
// New
func New(text string) error {
return &errorString{text}
}
// errorString error ( )
type errorString struct {
s string
}
func (e *errorString) Error() string {
return e.s
}
package main
import (
"errors"
"fmt"
)
func main() {
fmt.Println(errors.New(" "))
}
// Errorf , error
func Errorf(format string, a ...interface{}) error {
return errors.New(Sprintf(format, a...))
}
package main
import (
"fmt"
)
func main() {
const name, id = "bimmler", 17
err := fmt.Errorf("user %q (id %d) not found", name, id)
if err != nil {
fmt.Print(err)
}
}
내장 함수
panic
는 실행 중 오류가 발생할 수 있으며, 이 함수를 호출하면 현재goroutine
는 정상적인 실행 절차를 정지합니다.이런 상황은 일반적으로 일부 중요한 매개 변수가 부족한 검사를 할 때 발생한다. 만약에 이 매개 변수가 부족하면 프로그램이 정상적으로 운행하지 못하게 하기 때문에 프로그램을 계속 운행하게 하는 것보다 (근본적으로 정상적으로 운행할 수 없을 수도 있다) 제때에 중지하게 하는 것이 낫다.func panic(v interface{})
이 함수는 임의의 형식의 실참 (일반적으로 문자열) 을 받아들여 프로그램이 끝날 때 인쇄합니다.
package main
func main() {
panic(" 。")
}
다른 유형에서는 장면을 사용합니다.
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("wait for init...")
}
var user = os.Getenv("USER")
func init() {
//
if user == "" {
panic("no value for $USER")
}
}
일반적인 상황에서 우리는panic, 특히 라이브러리 함수에서 사용하는 것을 피해야 한다.
panic
가 호출된 후 (명확하지 않은 실행 중 오류, 예를 들어 수조나 절편 인덱스 월, 유형 단언 실패) 등은 현재 함수의 실행을 즉시 중지하고 goroutine
창고를 거슬러 올라가 지연된 함수를 실행합니다.goroutine
창고의 맨 위에 거슬러 올라가면 프로그램이 종료됩니다.가령 함수
F
가 호출되었다고 가정하면panic
의 정상적인 실행은 즉시 중단됩니다.F
중 지연된 함수는 순서대로 실행되고 F
호출처로 되돌아옵니다.호출자F
에 대해서도 이 때 G
함수를 호출하는 것처럼 실행을 멈추고 panic
지연된 모든 함수를 거슬러 올라가기 시작합니다.이 G
의 모든 함수가 멈출 때까지 계속 거슬러 올라가면 프로그램이 종료되고 오류 정보를 보고합니다. goroutine
에게 전달된 매개 변수를 포함합니다.물론 우리는 내장함수
panic
를 사용하여 복구하고 recover
의 제어권을 되찾아 계속 아래를 볼 수 있다.우리는 defer 문장 한 문장에서
goroutine
창고는 defer
순서로 집행된다고 언급한 적이 있다.3 Recover(복구)
내장 함수LIFO
는 발생recover
한panicking
을 정상적으로 운행할 수 있다.지연된 함수에서 실행goroutine
하면 recover
의 발생을 중지할 수 있습니다.주의는 지연된 함수에 직접 있어야 합니다.지연 함수에서 (또는 간접적으로) 이 함수를 호출하지 않으면 아무런 작용도 일어나지 않고 panic
되돌아옵니다.프로그램이 발생하지 않았거나 nil
의 매개 변수가 panic
이면 panic
의 반환값도 nil
입니다.func recover() interface{}
다음 예제에서는 panic과 recover의 작업 메커니즘을 보여 줍니다.package main
import "fmt"
func main() {
f()
fmt.Println(" f() 。")
}
func f() {
defer func() {
if r := recover(); r != nil {
fmt.Println(" f() 。", r)
}
}()
fmt.Println(" g()。。。")
g(0)
fmt.Println(" g() 。")
}
func g(i int) {
if i > 3 {
fmt.Println("Panicking!")
panic(fmt.Sprintf("%v", i))
}
defer fmt.Println(" g() ", i)
fmt.Println(" g() ", i)
g(i + 1)
}
func h() {
fmt.Println("hello")
}
effective_ 보기go의 예:
서버에서 실패 recover
를 종료하고 다른 실행 중인 nil
을 죽일 필요가 없습니다.func server(workChan chan *Work) {
for work := range workChan {
go safelyDo(work)
}
}
func safelyDo(work *Work) {
defer func() {
if err := recover(); err != nil {
log.Println("work failed:", err)
}
}()
do(work)
}
복구 모드를 적절하게 사용하면 goroutine
함수(및 호출된 모든 코드)는 호출goroutine
을 통해 더 나쁜 결과를 피할 수 있다.우리는 이런 사상을 이용하여 복잡한 소프트웨어 중의 오류 처리를 간소화할 수 있다.do
패키지의 이상적인 버전을 보면 국부적인 오류 유형 호출 panic
으로 오류를 보고합니다.다음은 regexp
유형, panic
방법 및 Error
함수의 정의입니다.// Error , error 。
type Error string
func (e Error) Error() string {
return string(e)
}
// error *Regexp , Error Panic 。
func (regexp *Regexp) error(err string) {
panic(Error(err))
}
// Compile 。
func Compile(str string) (regexp *Regexp, err error) {
regexp = new(Regexp)
// ,doParse panic
defer func() {
if e := recover(); e != nil {
regexp = nil //
err = e.(Error) // , Panic。
}
}()
return regexp.doParse(str), nil
}
error
트리거된 경우 Compile
복구 블록은 반환 값을 doParse
로 설정합니다. 지연된 함수는 이름이 지정된 반환 값을 수정할 수 있습니다.panic
의 값을 부여하는 과정에서 우리는 그것이 국부적인 유형nil
을 가지고 있는지 단언함으로써 그것을 검사할 것이다.만약 그것이 없다면, 형식 단언은 실패할 것입니다. 실행 중 오류가 발생하고, 모든 것이 중단된 적이 없는 것처럼 창고의 거슬러 올라갑니다.이 검사는 색인 경계선 넘기 같은 의외의 사고가 발생하면 우리가 err
과 Error
을 사용하여 해석 오류를 처리하더라도 코드는 실패할 수 있음을 의미한다.
적절한 오류 처리를 통해 panic
방법(구체적인 유형에 귀속되는 방법이기 때문에 내장된 recover
유형과 이름이 같아도 상관없음)은 보고 오류를 쉽게 처리할 수 있고 거슬러 올라가는 해석 창고를 수동으로 처리할 염려가 없다.if pos == 0 {
re.error("'*' illegal at start of expression")
}
비록 이런 모델은 매우 유용하지만, 그것은 반드시 가방 안에서만 사용해야 한다.error
내부의 error
호출을 Parse
값으로 바꾸고 호출자에게 노출되지 않습니다.이것은 준수할 만한 좋은 규칙이다.
또 이런 재촉발panic
의 관용법은 실제 오류가 발생할 때error
의 값을 바꾼다.그러나 원시적이든 새로운 오류든 붕괴 보고서에 나타나기 때문에 문제의 근원은 여전히 볼 수 있다.이런 간단한 재촉발 panic
모델은 이미 충분하다. 왜냐하면 그것은 단지 붕괴일 뿐이다.그러나 원본 값만 표시하고 싶다면 코드를 많이 써서 필요하지 않은 문제를 필터한 다음 원본 값으로 다시 터치할 수도 있다panic
.
참조:https://golang.org/doc/effective_go.html#errors https://golang.org/pkg/builtin/#error https://blog.golang.org/defer-panic-and-recover
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Go Fiber 및 PlanetScale로 REST API 구축 - 4부
다시 사용자 핸들러에 UpdateUser라는 새 함수를 추가합니다.
업데이트 사용자를 main.go에 등록
이제 응용 프로그램을 다시 실행하십시오.
이전에 생성한 사용자를 업데이트합니다.
응답
사용자가 존재하지 않을...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.
func recover() interface{}
package main
import "fmt"
func main() {
f()
fmt.Println(" f() 。")
}
func f() {
defer func() {
if r := recover(); r != nil {
fmt.Println(" f() 。", r)
}
}()
fmt.Println(" g()。。。")
g(0)
fmt.Println(" g() 。")
}
func g(i int) {
if i > 3 {
fmt.Println("Panicking!")
panic(fmt.Sprintf("%v", i))
}
defer fmt.Println(" g() ", i)
fmt.Println(" g() ", i)
g(i + 1)
}
func h() {
fmt.Println("hello")
}
func server(workChan chan *Work) {
for work := range workChan {
go safelyDo(work)
}
}
func safelyDo(work *Work) {
defer func() {
if err := recover(); err != nil {
log.Println("work failed:", err)
}
}()
do(work)
}
// Error , error 。
type Error string
func (e Error) Error() string {
return string(e)
}
// error *Regexp , Error Panic 。
func (regexp *Regexp) error(err string) {
panic(Error(err))
}
// Compile 。
func Compile(str string) (regexp *Regexp, err error) {
regexp = new(Regexp)
// ,doParse panic
defer func() {
if e := recover(); e != nil {
regexp = nil //
err = e.(Error) // , Panic。
}
}()
return regexp.doParse(str), nil
}
if pos == 0 {
re.error("'*' illegal at start of expression")
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Go Fiber 및 PlanetScale로 REST API 구축 - 4부다시 사용자 핸들러에 UpdateUser라는 새 함수를 추가합니다. 업데이트 사용자를 main.go에 등록 이제 응용 프로그램을 다시 실행하십시오. 이전에 생성한 사용자를 업데이트합니다. 응답 사용자가 존재하지 않을...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.