2013-11-23 1 views
5

나는 다음과 같은 유형이 : 내가 왜 함수의 매우 잘 이해하고 있다고 생각전화 이동 기능 (B가 구현 A)

type Statement interface { 
    Say() string 
} 

type Quote struct { 
    quote string 
} 

func (p Quote) Say() string { 
    return p.quote 
} 

func Replay(conversation []Statement) { 
    for _, statement := range conversation { 
     fmt.Println(statement.Say()) 
    } 
} 

을 그 []Statement 유형의 매개 변수를 허용하고 []Quote과 함께 호출 할 수 없습니다. QuoteStatement을 구현하더라도 []Quote[]Statement을 구현하지 않습니다. []Statement도 인터페이스가 아닙니다. 유형은 slice of Statement입니다. Go가 형식에서 인터페이스 형식으로 암시 적으로 변환하는 동안 형식 A의 조각에서 인터페이스 B의 조각으로 암시 적 변환을 수행하지 않습니다.

우리는 명시 적으로 문에 따옴표를 변환 할 수 있습니다

conversation := []Quote{ 
    Quote{"Nice Guy Eddie: C'mon, throw in a buck!"}, 
    Quote{"Mr. Pink: Uh-uh, I don't tip."}, 
    Quote{"Nice Guy Eddie: You don't tip?"}, 
    Quote{"Mr. Pink: Nah, I don't believe in it."}, 
    Quote{"Nice Guy Eddie: You don't believe in tipping?"}, 
} 

// This doesn't work 
// Replay(conversation) 

// Create statements from quotes 
statements := make([]Statement, len(conversation)) 
for i, quote := range conversation { 
    statements[i] = quote 
} 

Replay(statements) 

는 이제 재생 그것을 재생을 사용하는 것이 얼마나 쉬운 그 길에서 가고 싶은 도서관의 일부라고. 이 객체를 사용하면 Statement 인터페이스를 구현하는 한 객체 조각으로 Replay를 호출 할 수 있습니다. 이렇게하려면 그것을 가지고 다음과 같은 변환 방법 :

func Replay(its interface{}) { 
    conversation := ConvertToStatements(its) 
    for _, statement := range conversation { 
     fmt.Println(statement.Say()) 
    } 
} 

우리는 지금 직접 따옴표와 함께 재생을 호출 할 수 있습니다 :

func ConvertToStatements(its interface{}) ([]Statement, error) { 
    itsValue := reflect.ValueOf(its) 
    itsKind := itsValue.Kind() 
    if itsKind != reflect.Array && itsKind != reflect.Slice { 
     return nil, fmt.Errorf("Expected items to be an Array or a Slice, got %s", itsKind) 
    } 
    itsLength := itsValue.Len() 
    items := make([]Statement, itsLength) 
    for i := 0; i < itsLength; i++ { 
     itsItem := itsValue.Index(i) 
     if item, ok := itsItem.Interface().(Statement); ok { 
      items[i] = item 
     } else { 
      return nil, fmt.Errorf("item #%d does not implement the Statement interface: %s", i, itsItem) 
     } 
    } 
    return items, nil 
} 

재생은 다음과 같습니다

Replay(conversation) 

마지막으로, 내 질문 : A가 Statement 인터페이스를 구현하는 한 Replay가 A 유형의 슬라이스를 허용 할 수있는 더 간단한 방법이 있습니까?

답변

2

당신 (긴) 질문에 짧은 대답은 : 제

내가 ConvertToStatment 및 재생이 빈 인터페이스를 복용의 솔루션은 "좋은"해결책이라고 생각하지 않는다 : 나는 func Replay([]Statement)을 원합니다 발신자는 Statements 슬라이스를 제공해야합니다. 이것은 훨씬 명확하고 호출자는 자신의 내용을 [] 문으로 변환하거나 [] 문을 직접 생성 할 수 있습니다.

5

[]Quote 슬라이스의 메모리 내 레이아웃이 []Statement 슬라이스와 다르므로이 방법을 사용할 수 없습니다.

[]Quote 슬라이스의 배킹 배열은 Quote 구조체로 구성되며, []Statement 슬라이스의 배킹 배열은 인터페이스 변수로 구성됩니다. Quote 구조체 (또는 인터페이스를 구현하는 다른 유형)를 보유하는 것뿐만 아니라 인터페이스 변수는 포함 된 값에 대한 정보를 입력하는 포인터도 저장합니다. 이것은 Say 메서드 호출을 디스패치하는 방법을 결정하는 데 필요합니다.

다른 데이터 레이아웃을 사용하면 안전하지 않은 캐스팅이 아닌 두 슬라이스 유형을 교환 할 수 없습니다. 한 유형이 있고 다른 유형이 필요한 경우 두 유형을 수동으로 변환해야합니다.

0

다음 코드에는 Say() 함수를 구현하는 두 가지 구조 유형이 있습니다.당신은 두 가지 유형을 포함하는 배열을 생성하고 Replay()를 호출하고 당신이 원하는 것을 할 수 있습니다 :

package main 

import "fmt" 

type Statement interface { 
    Say() string 
} 
type Statements []Statement 

type Quote struct { 
    quote string 
} 
type Quotes []Quote 

func (p Quote) Say() string { 
    return p.quote 
} 

type Attributed struct { 
    who string 
    quote string 
} 

func (p Attributed) Say() string { 
    return p.who + ": " + p.quote 
} 


func Replay(conversation []Statement) { 
    for _, s := range conversation { 
     fmt.Println(s.Say()) 
    } 
} 

func (q Quotes) toStatements() Statements { 
    conv := make(Statements, len(q)) 
    for i, v := range q { 
     conv[i] = Statement(v) 
    } 
    return conv 
} 

func main() { 
    conversation := Statements{ 
     Quote{"Nice Guy Eddie: C'mon, throw in a buck!"}, 
     Quote{"Mr. Pink: Uh-uh, I don't tip."}, 
     Attributed{"Nice Guy Eddie", "You don't tip?"}, // <= another type 
     Quote{"Mr. Pink: Nah, I don't believe in it."}, 
     Quote{"Nice Guy Eddie: You don't believe in tipping?"}, 
    } 

    myquotes := Quotes{ 
     Quote{"Nice Guy Eddie: C'mon, throw in a buck!"}, 
     Quote{"Mr. Pink: Uh-uh, I don't tip."}, 
     Quote{"Nice Guy Eddie: You don't tip?"}, 
     Quote{"Mr. Pink: Nah, I don't believe in it."}, 
     Quote{"Nice Guy Eddie: You don't believe in tipping?"}, 
    } 

    Replay(conversation) 
    Replay(myquotes.toStatements()) 
} 

Replay()

변경하거나 Attributed{}에 대해 아무것도 알지 못한다. 슬라이스 유형을 입력해야합니다. Quotes & Statements.