2017-05-11 21 views
1

나는 구h 주걱을 OOP 방식으로 행동하려고 시도하고 있다고 생각하지만, 내가 원하는 것을하기 위해 이동하는 숙어를 모른다. 예를 들어, 명령의 번호Go : 콘크리트 유형이 어떤 내장 유형인지 확인하려면 어떻게해야합니까?

여기
type Message struct { 
    ID string  `json:"id,omitempty"` 
    Type string  `json:"type"` 
    Data interface{} `json:"data"` 
} 

데이터는 여러 가지가 될 수 있습니다 :

type Command struct { 
    User *types.UserInfo `json:"user"` 
} 

type CommandA struct { 
    Command 
    A *AData `json:"a_data"` 
} 

type CommandB struct { 
    CommandB 
    B *BData `json:"b_data"` 

} 

은 내가 클라이언트 - 서버 응용 프로그램에서 주위에 데이터를 전달하는 데 사용하는 메시지 구조체를

내가 원하는 일은 메시지 데이터 유형이 Command인지 확인하고 모든 명령에 공통적으로 적용되는 조치 (예 : 권한 부여)를 한 곳에서 수행하고 어떤 유형의 명령을 입력 할 필요없이 해당 명령을 호출하는 것입니다 핸들러 함수를 호출 한 다음 auth를 th 거대한 코드 중복을 초래할 것입니다.

아래 코드는 내가하고 싶은 것을 반영합니다.

for { 
    select { 
    case m := <-in: 
     // what I would like to do, obviously not working as 
     // m.Data is not of type Command but the actual command type 
     if c, ok := m.Data.(msg.Command); ok { 
     // do auth and other common stuff 
     } 
     switch t := m.Data.(type) { 
     case *msg.CommandA: 
     go srv.handleCommandA(m.ID, t) 
     case *msg.CommandB: 
     go srv.handleCommandB(m.ID, t) 
     // etc etc 
     default: 
     // do something 
     } 
    } 
} 

어떻게 해결합니까?

답변

2

type Commander interface{ 
    DoCommonStuff() 
} 

명령 구조체

func (c Command) DoCommonStuff(){ 
//do stuff 
} 

위해 그것을 구현하고

if c, ok := m.Data.(Commander); ok { 
    c.DoCommonStuff() 
} 

다른 코드를 주장 변화가 없어야한다. d

+0

그리고 '데이터'가 항상 어떤 종류의 명령 일 것이라는 것을 알고 있다면 구조체의 형식을'Commander'로 변경하고 형식 어설 션을 제거하고 부팅 할 수있는 몇 가지 유형 안전을 얻을 수 있습니다. – Adrian

0

하나의 접근법은 반사를 사용하여 Data에서 공통 필드 값을 추출하는 것입니다. 귀하의 예에서 모든 CommandUser 필드를 가지므로 Message.Data이 명령인지 여부를 식별하는 데 사용할 수 있습니다. Command이 데이터에 삽입되지 않은 경우 nil을 반환하면됩니다. 예제 코드 : 당신은 인터페이스에서 일반적인 명령 물건을 정의 할 수 있습니다

func GetUserInfo(v interface{}) *types.UserInfo { 
    vt := reflect.ValueOf(v) 
    if vt.Kind() == reflect.Ptr { 
     vt = vt.Elem() 
    } 
    if vt.Kind() != reflect.Struct { 
     return nil 
    } 

    u := vt.FieldByName("User") 
    if !u.IsValid() { 
     return nil 
    } 

    user, ok := u.Interface().(*types.UserInfo) 
    if !ok { 
     return nil 
    } 

    return user 
} 

//Call GetUserInfo then perform common operation 
user := GetUserInfo(m.Data) 
if user != nil { 
    //Do auth and other common stuff 
}