Go: 인터페이스를 unexported로 만들어 봐.
일단 unexported.
Go에서 동작을 추상화할 때 인터페이스를 사용합니다.
또 인터페이스 분리의 원칙(ISP)을 준수하는 등 드문드문 결합된 코드를 쓸 때 호출자가 요구하는 인터페이스를 사용하지 않는 방법에 의존하지 않도록 정의한다.
코드를 이렇게 쓰면 Go의 유형은 은근히 인터페이스를 충족시키기 때문에 처음부터 export 인터페이스가 필요하지 않겠죠.
위에서 말한 바와 같이 Go에서 유형은 인터페이스를 실현하는 방법에서 이 인터페이스를 만족시킨다(예를 들어 사용하지 않아도 된다
implement
등 명시).즉 인터페이스가 unexported라고 해도 인터페이스에 unexported 방법이 없으면 외부 포장의 유형도 인터페이스를 충족시킬 수 있다는 것이다.package main
// ...
func greetTo(w io.Writer, g greeter) {
fmt.Fprintln(w, g.Greet())
}
type greeter interface {
Greet() string
}
package l10n
type JA struct{}
func (JA) Greet() string {
return "こんにちは"
}
type EN struct{}
func (EN) Greet() string {
return "Hello"
}
l10n
패키지JA
와EN
패키지main
인터페이스가 충족되기 때문에greeter
패키지main
함수의 두 번째 매개 변수는 전달할 수 있다.package main
import (
"errors"
"flag"
"fmt"
"io"
"os"
"github.com/tomocy/go-if/l10n"
)
var greeters = map[string]greeter{
"ja": l10n.JA{}, // l10n.JAはgreeterインターフェイスを満たす
"en": l10n.EN{}, // l10n.ENはgreeterインターフェイスを満たす
}
func main() {
if err := run(os.Stdout, os.Args); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func run(w io.Writer, args []string) error {
if len(args) < 1 {
return errors.New("too few arguments")
}
flags := flag.NewFlagSet(args[0], flag.ContinueOnError)
lang := flags.String("lang", "ja", "language to greet")
if err := flags.Parse(os.Args[1:]); err != nil {
return err
}
g, ok := greeters[*lang]
if !ok {
return fmt.Errorf("unsupported language: %s", *lang)
}
greetTo(w, g)
return nil
}
func greetTo(w io.Writer, g greeter) {
fmt.Fprintln(w, g.Greet())
}
type greeter interface {
Greet() string
}
확실합니다. greetTo
처럼 많은 포장에서 (파라미터나 유형 필드의 유형으로) 사용할 때 인터페이스를 export할 수 있습니다.func main() {
if err := run(os.Stdout, os.Args); err != nil {
fmt.Fprintln(os.Stderr)
os.Exit(1)
}
}
func run(w io.Writer, args []string) error {
// ...
}
상기 코드는 io.Writer
덕분에 매번 정의io.Writer
와 같은 인터페이스가 필요 없고 각 포장이 조화롭다.그러나 이런 상황에서 (이 인터페이스는 매우 일반적인 행동거지를 나타낸다) 사실 매우 드물다. 많은 경우 ISP를 보호하면서 unexported로 정의할 수 있지 않겠는가.이 경우 다소 중복되는 경우가 있을 것 같은데, 이 부분을 위해 의존도를 높이는 것보다 결합도를 낮추는 게 더 중요하지 않겠나.
A little copying is better than a little dependency.
Go Proverbs - Rob Pike - Gopherfest - November 18, 2015
또한 인터페이스에 방법을 추가할 때 후방 호환성을 갖추지 못하기 때문에 인터페이스 export를 많은 포장에 사용하고 사용법을 알게 된 후에도 늦지 않을 것입니다.
doNotImplement
참고로 위에서 말한 바와 같이 인터페이스의 exported, unexported를 막론하고 unexported 방법을 인터페이스에 추가하면 외부 포장 형식이 만족할 수 없는 인터페이스를 만들 수 있다.
package main
// ...
type greeter interface {
doNotImplement
Greet() string
}
type doNotImplement interface {
doNotImplement()
}
package l10n
// ...
type JA struct{}
func (JA) Greet() string {
return "こんにちは"
}
func (JA) doNotImplement() {}
아까 예시된 io.Writer
패키지의 main
인터페이스에 unexported를 추가하는 방법이 있다면 greeter
패키지의 l10n
또는 JA
방법이 있어도 EN
어느 것도 만족하지 않기 때문doNotImplement
인터페이스컴파일 오류는 다음과 같습니다../main.go:14:2: cannot use l10n.JA literal (type l10n.JA) as type greeter in map value:
l10n.JA does not implement greeter (missing doNotImplement method)
have l10n.doNotImplement()
want doNotImplement()
./main.go:15:2: cannot use l10n.EN literal (type l10n.EN) as type greeter in map value:
l10n.EN does not implement greeter (missing doNotImplement method)
have l10n.doNotImplement()
want doNotImplement()
Reference
이 문제에 관하여(Go: 인터페이스를 unexported로 만들어 봐.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/tomocy/articles/7799bdcf716ca386c6da텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)