struct 내zerovalue 처리 방법
14606 단어 Go
흐름도
배경.
go는null의 안전한 언어가 아닙니다.뿐만 아니라 수신기는nil시 처리도 쓸 수 있다1.
nil 수신기의 활용 예시
package main
import "fmt"
type Name struct {
First string
Last string
}
func (n *Name) String() string {
if n == nil {
return "N/A"
}
return fmt.Sprintf("%s, %s", n.Last, n.First)
}
func main() {
name := &Name{"Taro", "Yamada"}
fmt.Println(name.String()) // => Yamada, Taro
name = nil
fmt.Println(name.String()) // => N/A
}
한편,interface의zerovalue는nil이며, 이 방법을 호출하면 무효가 되어 유감입니다.누르보의 예
package main
import (
"bufio"
"io"
"os"
)
type Command struct {
Input io.Reader
Output io.Writer
}
func (c *Command) Run() {
scanner := bufio.NewScanner(c.Input)
scanner.Scan()
c.Output.Write(scanner.Bytes())
}
func main() {
c := &Command{} // Oops! 初期化し忘れた。
c.Run() // => SEGV
}
그럼 이 문제를 어떻게 처리해야 하나요?오류 처리
물론 닐이 있는 이상 이 상황을 고려해 처리해야 한다.
상기 "잘못된 예시"의 오류 처리 버전
package main
import (
"bufio"
"errors"
"io"
"os"
)
type Command struct {
Input io.Reader
Output io.Writer
}
func (c *Command) Run() error {
if c.Input == nil || c.Output == nil {
return errors.New("both Input and Output should be non-nil")
}
scanner := bufio.NewScanner(c.Input)
scanner.Scan()
c.Output.Write(scanner.Bytes())
return nil
}
func main() {
c := &Command{}
fmt.Println(c.Run())
}
error 처리로 패닉을 사용하는 부작용이 너무 강하기 때문에 피하는 것이 좋다(see 부록).기본값 준비
error를 대체하는 수단으로 기본값을 준비하는 방법도 자주 사용된다.
상기 "누르보의 예"의 기본값 처리 버전
package main
import (
"bufio"
"io"
"os"
)
var DefaultInput io.Reader = os.Stdin
var DefaultOutput io.Writer = os.Stdout
type Command struct {
Input io.Reader
Output io.Writer
}
func (c *Command) input() io.Reader {
if c.Input != nil {
return c.Input
}
return DefaultInput
}
func (c *Command) output() io.Writer {
if c.Output != nil {
return c.Output
}
return DefaultOutput
}
func (c *Command) Run() {
scanner := bufio.NewScanner(c.input())
scanner.Scan()
c.output().Write(scanner.Bytes())
}
func main() {
c := &Command{}
c.Run()
}
예를 들어 http.Server는 &http.Server{}
에서 사용한 가설일 수도 있고 기본값에 대한 설명이 많다.총결산
Go에서 제로value를 마음대로 생성하기 때문에 error 처리를 정확하게 하고 기본값을 준비할 필요가 있습니다.
당연한 것 같지만 실제로 해보면 촌스러운 기술을 쓰기 때문에 타협하기 쉽다.
지금의 언어로 지능적으로 이 문제를 해결하는 것은 어려울 것 같다2. 근육으로 해결하는 것이 상책이다3.
부록
error에 오류가 없다는 전제로panic가 사용할 수 있는 상황을 고려해 보세요.
가능:assersion의 사용법.예를 들어 Must 함수입니다.
유명한 곳으로는 regexp.MustCompile과template.Must가 있다.
이것은 assersion의 생각에 가깝다.아니, Must 버전도 같이 준비해야지.
허용: 단독 함수에서 전달된 매개 변수가 정확하지 않은 경우
예: template.JSEscape.
호출자에게 파라미터를 검사하라고 요구할 수도 있다.
미묘함: 매개 변수로 발생하지만 내부 상태에 의존하는 상황
예로func (*ServeMux) Handle.
pattern이 로그인했을 때panic가 했지만 조금 위험한 규격입니다.
Bad: 내부 상태에서만 발생
상술한'누르보의 예'는 일치한다.매개 변수와 상관없이 내부 상태에서만 발생하는 상황.
recover를 전제로 편성했다면 받아들일 수 있었을 텐데 go에 맞지 않는 실상이었다.
부록: 첫 번째 그림 출처
@startuml
(*) --> "struct内のZero valueの対処"
if "デフォルト値で処理 vs. エラー処理" then
-left-> [デフォルト値で処理] "デフォルト値を用意する"
if "デフォルトを変更可能にするか?" then
--> [yes] "グローバルにexportedな形で配置する"
if "nilを入れられた時どうするか"
--> [error] "安全 :)"
else
--> [panic] "ベストではないが妥協ラインではある :("
endif
else
--> [no] "exportしない"
endif
else
-right-> [エラー処理] "エラーを適切に処理する"
if "errorを返す vs. panicにする"
--> [error] "安心 :)"
else
--> [panic] "ドキュメントに記載はするだろうが、あまりよくはない :("
endif
endif
@enduml
그럼에도 불구하고 나는 가능한 한 피하는 것이 좋겠다고 생각한다.그나저나 Objective-c에서는 nil 수신기의 정보 발송이 무시되었다.Ruby(method mising에서 Hack하지 않는 경우) NoMethod Error에서 ↩ 나는 null이 안전할 필요는 전혀 없다고 생각하지만, 나는 일부의non-nil 보증을 원한다.
func (r io.Reader non-nil)
이런 인상. ↩ 주입 의존에 관해서는 struct를 이용한 embed의 복안이 있기 때문에 총괄하고 싶습니다. ↩
Reference
이 문제에 관하여(struct 내zerovalue 처리 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/s-shin/items/a6e6b5322f2ecbd96745텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)