2014-12-02 2 views
4

확인. 나는 이것이 FAQ 인 것을 알고 있으며, 대답은 "포기하고, 그렇게하지 않습니다"라고 생각하지만, 나는 단지 뭔가를 놓치고 있지 않다는 것을 확실히하고 싶습니다.Go에서 인터페이스를 통한 분리 ... 인터페이스 구현 자의 조각?

나는 여전히 인터페이스 사용을위한 모범 사례와 규칙에 대해 머리를 감싸고 있습니다. 내가 분리 할 유지하기 원합니다 다른 패키지 코드를, 그래서 같은 일이 (작동하지 않는, 또는 여기되지 않을 것) :이

package A 

type Foo struct {} 

func (f *Foo) Bars() ([]*Foo, error) { 
    foos := make([]*Foo, 0) 

    // some loop which appends a bunch of related *Foo to foos 
    return foos, nil 
} 

package B 

type Foolike interface { 
    Bars() []Foolike 
} 

func DoSomething(f Foolike) error { 
    // blah 
} 

을의 컴파일러는 불평 :

cannot use f (type *A.Foo) as type Foolike in argument to B.DoSomething: 
*A.Foo does not implement Foolike (wrong type for Bars method) 
    have Bars() ([]*A.Foo, error) 
    want Bars() ([]Foolike, error) 

을 지금, [] Foolike가 인터페이스 서명 자체 아니라고 grok 수; 이것은 Foolike 인터페이스 조각에 대한 서명입니다. 나는 컴파일러가 A.Foo와 [] Foolike를 다른 것으로 취급하기 때문에 ... () 메모리 할당, 엄격한 타이핑 mumble).

내 질문은 : 궁극적으로 원하는대로 할 수있는 올바른 방법이 있습니까? B.DoSomething()이 A.Foo를 가져 오지 않고 B.DoSomething에서 * A.Foo를 사용하지 않고 받아 들일 수있게하는 것입니다.() 함수의 시그니처 (또는 인터페이스 정의에서 악화)? 나는 컴파일러를 속이거나 미친 런타임 속임수에 빠지려고 노력하지 않고있다. 아마 Foo.Bars()의 구현을 Foolike를 반환하도록 변경할 수 있다는 것을 이해합니다.하지만 바보 같고 잘못되었습니다 (왜 B에 대해 알아야할까요?). 디커플링의 모든 요소가 깨졌습니다.

다른 옵션은 인터페이스를 구현하기위한 요구 사항으로 Bars()를 제거하고 다른 방법을 사용하여 요구 사항을 적용하는 것입니다. 그게 이상적이라고 느껴진다. (Bars()가 유일하게 수출 된 방법 일까?). 편집 : 아니요, DoSomething()에서 Bars()를 사용할 수 없기 때문에 인터페이스에 정의되어 있지 않으므로 작동하지 않습니다. 한숨.

만약 내가 Doing It Wrong ™이라면, 나는 그것을 받아 들여 다른 것을 생각해 낼 것이다. 그러나 나는 그것이 어떻게 작동해야하는지에 대한 몇 가지 측면을 알기를 희망하지 않는다.

+0

디커플링이 한 가지입니다. 그러나 재귀 적으로 인터페이스를 정의하면 지금까지만 갈 수 있습니다.그렇다면'A' 패키지는'B' 패키지를 가져와야합니다. – seong

+1

메일 링리스트 (https://groups.google.com/forum/#!forum/golang-nuts)에 게시하시는 것이 좋습니다. devs 자주 거기에서 자주 나는 생각한다. 그런 다음 여기에 답변을 게시 할 수 있습니다. – korylprince

+1

'f.Bars'를 반환하는 것에 대한 성 (song)의 대답은 우리가 가진 문제 설명과 함께 볼 때 가장 좋습니다. - 유스 케이스를 설명 할 수 있다면 (예 :'Foo'와' 막대기는 진짜로, 등등이다) 어쩌면 조각 또는 무엇이든을 제외하고 무언가를 돌려 보내는 포함하는 영리한 방법이있다. 그러나 그렇지 않을 수도 있습니다. – twotwotwo

답변

1

오류 메시지에 따르면 []FooLike[]*Foo 유형을 서로 바꿔서 처리 할 수 ​​없습니다. 는 A []*Foo 슬라이스를 들어

, 메모리에 다음과 같이 보일 것이다 보조 배열 : 직선 앞으로 우리가 값이 유형 *Foo 될거야 알고 있기 때문에

| value1 | value2 | value3 | ... | valueN | 

, 그들은 저장할 수 있습니다 순차적으로 방법. 대조적으로, []FooLike 슬라이스의 각 요소는 다른 유형일 수 있습니다 (단, FooLike을 준수해야합니다).

| type1 | value1 | type2 | value2 | type3 | value3 | ... | typeN | valueN | 

그래서는 유형 간의 단순한 캐스팅을 할 수 없습니다 : : 그래서 보조 배열은 더 같을 것이다 새 슬라이스를 만들 필요하고 값을 복사합니다.

그래서 기본 유형이 작동하려면 인터페이스 유형의 슬라이스를 리턴해야합니다.