sort
꾸러미:
type Interface interface {
Len() int
Less(i, j int) bool
Swap(i, j int)
}
...
type reverse struct {
Interface
}
Interface
struct에서 익명 인터페이스의 의미는 무엇입니까 reverse
?
답변
이런 식으로 reverse는를 구현 sort.Interface
하고 다른 모든 메소드를 정의하지 않고도 특정 메소드를 재정의 할 수 있습니다.
type reverse struct {
// This embedded Interface permits Reverse to use the methods of
// another Interface implementation.
Interface
}
여기에서 어떻게 (j,i)
대신 스왑되는지 주목하십시오. (i,j)
또한 이것은 구현 reverse
하더라도 구조체에 대해 선언 된 유일한 메서드입니다.reverse
sort.Interface
// Less returns the opposite of the embedded implementation's Less method.
func (r reverse) Less(i, j int) bool {
return r.Interface.Less(j, i)
}
이 메서드 내에서 전달되는 구조체가 무엇이든 우리는 그것을 새로운 reverse
구조체 로 변환합니다 .
// Reverse returns the reverse order for data.
func Reverse(data Interface) Interface {
return &reverse{data}
}
이 접근 방식이 가능하지 않다면 무엇을해야할지 생각한다면 진정한 가치가 있습니다.
- ?에 다른
Reverse
방법을 추가 하십시오sort.Interface
. - 다른 ReverseInterface를 만드시겠습니까?
- …?
이러한 변경에는 표준 역방향 기능을 사용하려는 수천 개의 패키지에 걸쳐 더 많은 코드 줄이 필요합니다.
답변
좋아, 받아 들인 대답은 이해하는 데 도움이되었지만 내 사고 방식에 더 적합한 설명을 게시하기로 결정했습니다.
“효과적인 이동” 임베디드 다른 인터페이스를 가진 인터페이스의 예를 가지고 :
// ReadWriter is the interface that combines the Reader and Writer interfaces.
type ReadWriter interface {
Reader
Writer
}
다른 구조체가 포함 된 구조체 :
// ReadWriter stores pointers to a Reader and a Writer.
// It implements io.ReadWriter.
type ReadWriter struct {
*Reader // *bufio.Reader
*Writer // *bufio.Writer
}
그러나 인터페이스가 내장 된 구조체에 대한 언급은 없습니다. 나는 이것을 sort
패키지로 보고 혼란 스러웠다 .
type Interface interface {
Len() int
Less(i, j int) bool
Swap(i, j int)
}
...
type reverse struct {
Interface
}
그러나 아이디어는 간단합니다. 다음과 거의 동일합니다.
type reverse struct {
IntSlice // IntSlice struct attaches the methods of Interface to []int, sorting in increasing order
}
IntSlice
로 승격되는 방법 reverse
.
이:
type reverse struct {
Interface
}
즉, sort.reverse
인터페이스를 구현하는 모든 구조체 sort.Interface
와 인터페이스 에있는 모든 메서드를 포함 할 수 있으며 reverse
.
sort.Interface
방법이 Less(i, j int) bool
지금 대체 할 수 있습니다 :
// Less returns the opposite of the embedded implementation's Less method.
func (r reverse) Less(i, j int) bool {
return r.Interface.Less(j, i)
}
이해의 혼란
type reverse struct {
Interface
}
구조체는 항상 고정 된 구조, 즉 고정 된 유형의 필드 수가 고정되어 있다고 생각했습니다.
그러나 다음은 내가 틀렸다는 것을 증명합니다.
package main
import "fmt"
// some interface
type Stringer interface {
String() string
}
// a struct that implements Stringer interface
type Struct1 struct {
field1 string
}
func (s Struct1) String() string {
return s.field1
}
// another struct that implements Stringer interface, but has a different set of fields
type Struct2 struct {
field1 []string
dummy bool
}
func (s Struct2) String() string {
return fmt.Sprintf("%v, %v", s.field1, s.dummy)
}
// container that can embedd any struct which implements Stringer interface
type StringerContainer struct {
Stringer
}
func main() {
// the following prints: This is Struct1
fmt.Println(StringerContainer{Struct1{"This is Struct1"}})
// the following prints: [This is Struct1], true
fmt.Println(StringerContainer{Struct2{[]string{"This", "is", "Struct1"}, true}})
// the following does not compile:
// cannot use "This is a type that does not implement Stringer" (type string)
// as type Stringer in field value:
// string does not implement Stringer (missing String method)
fmt.Println(StringerContainer{"This is a type that does not implement Stringer"})
}
답변
진술
type reverse struct {
Interface
}
reverse
인터페이스를 구현하는 모든 항목 으로 초기화 할 수 있습니다 Interface
. 예:
&reverse{sort.Intslice([]int{1,2,3})}
이렇게하면 포함 된 Interface
값에 의해 구현 된 모든 메서드 가 외부로 채워지면서 에서 일부 메서드 를 재정의 할 수 있습니다 ( reverse
예 : Less
정렬을 반대로).
를 사용할 때 실제로 일어나는 일 sort.Reverse
입니다. spec의 struct 섹션에서 임베딩 에 대해 읽을 수 있습니다 .
답변
저도 설명하겠습니다. sort
패키지는 안 export 형을 정의 reverse
구조체, 그 퍼가기이다, Interface
.
type reverse struct {
// This embedded Interface permits Reverse to use the methods of
// another Interface implementation.
Interface
}
이를 통해 Reverse는 다른 인터페이스 구현의 메소드를 사용할 수 있습니다. 이것이 바로 composition
Go의 강력한 기능입니다.
에 대한 Less
메서드 는 포함 된 값 의 메서드를 reverse
호출 하지만 인덱스를 뒤집어 정렬 결과의 순서를 반대로합니다.Less
Interface
// Less returns the opposite of the embedded implementation's Less method.
func (r reverse) Less(i, j int) bool {
return r.Interface.Less(j, i)
}
Len
및 Swap
의 다른 두 메서드 는 포함 된 필드이므로 reverse
원래 Interface
값에 의해 암시 적으로 제공됩니다 . 내 보낸 Reverse
함수는 reverse
원래 Interface
값 이 포함 된 유형 의 인스턴스를 반환합니다 .
// Reverse returns the reverse order for data.
func Reverse(data Interface) Interface {
return &reverse{data}
}
답변
이 기능 은 테스트 에서 모의 를 작성할 때 매우 유용 합니다 .
다음은 그러한 예입니다.
package main_test
import (
"fmt"
"testing"
)
// Item represents the entity retrieved from the store
// It's not relevant in this example
type Item struct {
First, Last string
}
// Store abstracts the DB store
type Store interface {
Create(string, string) (*Item, error)
GetByID(string) (*Item, error)
Update(*Item) error
HealthCheck() error
Close() error
}
// this is a mock implementing Store interface
type storeMock struct {
Store
// healthy is false by default
healthy bool
}
// HealthCheck is mocked function
func (s *storeMock) HealthCheck() error {
if !s.healthy {
return fmt.Errorf("mock error")
}
return nil
}
// IsHealthy is the tested function
func IsHealthy(s Store) bool {
return s.HealthCheck() == nil
}
func TestIsHealthy(t *testing.T) {
mock := &storeMock{}
if IsHealthy(mock) {
t.Errorf("IsHealthy should return false")
}
mock = &storeMock{healthy: true}
if !IsHealthy(mock) {
t.Errorf("IsHealthy should return true")
}
}
사용하여:
type storeMock struct {
Store
...
}
모든 Store
방법 을 조롱 할 필요는 없습니다 . HealthCheck
이 방법 만 TestIsHealthy
테스트에 사용되므로 모의 처리 만 할 수 있습니다 .
test
명령 결과 아래 :
$ go test -run '^TestIsHealthy$' ./main_test.go
ok command-line-arguments 0.003s
이 사용 사례 의 실제 예 는 AWS SDK를 테스트 할 때 찾을 수 있습니다 .
더 분명하게하기 위해, 여기에 추악한 대안이 Store
있습니다. 인터페이스 를 만족시키기 위해 구현해야하는 최소한의 대안이 있습니다.
type storeMock struct {
healthy bool
}
func (s *storeMock) Create(a, b string) (i *Item, err error) {
return
}
func (s *storeMock) GetByID(a string) (i *Item, err error) {
return
}
func (s *storeMock) Update(i *Item) (err error) {
return
}
// HealthCheck is mocked function
func (s *storeMock) HealthCheck() error {
if !s.healthy {
return fmt.Errorf("mock error")
}
return nil
}
func (s *storeMock) Close() (err error) {
return
}