2014-11-18 3 views
0

Привет Я пытаюсь сделать что-то вроде следующего примера.Вызов struct from map of structs

Мой опыт работы с PHP-разработчиком (я знаю!) Затрудняет мне это. Я читал Законы размышлений и другие источники, но это над моей головой. Подход, который я использую, вероятно, ошибочен ... и надеюсь, что кто-то может указать мне в правильном направлении.

Использование этого в конкретном виде заключается в том, что версия 01 или 02 или 03 отправляется из внешнего параметра, на основании этого мне нужно получить соответствующую структуру и заполнить ее значениями базы данных.

package V01 
type Struct1 struct{ 
    Field1 string 
    Field2 string 
} 

type Struct2 struct{ 
    Field1 string 
    Field2 string 
} 

package V02 
type Struct1 struct{ 
    Field1 string 
    Field2 string 
    ExtraField1 string 
} 

type Struct2 struct{ 
    Field1 string 
    Field2 string 
    ExtraField2 string 
    ExtraField3 string 
} 

var VStructs = map[string]map[string]interface{}{ 
    "01": map[string]interface{}{ 
     "Struct1": V01.Struct1{}, 
     "Struct2": V01.Struct2{}, 
    }, 
    "02": map[string]interface{}{ 
     "Struct1": V02.Struct1{}, 
     "Struct2": V02.Struct2{}, 
    }, 
    "03" : map[string]interface{}{ 
     "Struct1": V01.Struct1{}, 
     "Struct2": V02.Struct2{}, 
    }, 
} 

// I get the struct fieldnames and so on. 
fmt.Printf("%+v\n", VStructs["01"]["Struct1"]) 

// I cannot access any of the fields though because it is an interface 
fmt.Println(VStructs["01"]["Struct1"].Field1) // PANIC! 

// Type Switching is not working either since the version can be variable. 
s := VStructs["01"]["Struct1"].Field1 
switch x := s.(type) { 
case reflect.Struct: // PANIC! reflect.Struct (type reflect.Kind) is not a type 
    fmt.Println("I am an struct") 
default: 
    fmt.Println("I am an no struct") 
} 

Так что, может быть, может показать мне подходящий способ сделать это. Или, может быть, функция-обертка, чтобы вернуть правильную структуру ... нет подсказки на этом этапе.

Надеюсь, что это ясно, и будет уточняться, если вас попросят.

+0

Вы должны использовать имена типов в тип переключателя, а не 'значения reflect.Kind'. То есть это должен быть 'case V01.Struct:' и т. д., а не 'case reflect.Struct:'. –

+0

@ Ainar-G, спасибо, но версии V01, V02, V03 являются переменными, поэтому это не вариант, особенно если в каждой версии около 50 структур. – DonSeba

+0

Затем вам нужно определить интерфейс для всех этих структур для реализации. –

ответ

0

Хорошо, так как вопрос, вероятно, был в конфликте с тем, как используется golang.

Я написал пакет, чтобы служить моим потребностям:

на основе выбранной версии (в URL или заголовка, что вы любите) мы извлечь карту структур. Теперь мы можем выбрать фактическую структуру, в которой мы нуждаемся, установить некоторые значения и, наконец, отправить ее обратно на экран или отправить ее в БД (в моем случае gorp).

Пакет можно найти здесь https://github.com/donseba/contractor/

0

Вы не можете получить доступ к структуре внутри карты таким образом, потому что не может быть никакой структуры. В вашем примере, что будет VStructs["foo"]["bar"].Field1 be? У вас не было бы способа узнать, действительно ли это пустая структура на карте, или нет ничего, и доступ к карте просто вернул вам пустое значение для этого типа. Вместо этого вы должны указать явную проверку:

v, ok := VStructs["01"]["Struct1"] 
if !ok { 
    // Handle the case of the missing struct. 
} 
// It is also a good practice to check type assertions. 
s, ok := v.(V01.Struct1) 
if !ok { 
    // Handle the case when v is not V01.Struct1. 
} 
f = s.Field1 
+0

Спасибо за ответ, но с вашим примером я получаю 'type interface {} не имеет поля или метода Поле1' – DonSeba

+0

@DonSeba Я не заметил, что у вас есть интерфейс' interface { } 'там. Отредактировал ответ, чтобы отразить это. –

+0

Проблема в том, что «V01.Struct1» может быть «V02.Struct1» .. извините.возможно, я пытаюсь что-то сделать динамичным, с golang .. – DonSeba