Итак, как я уже упоминал в комментарии, проще всего, если вы хотите иметь возможность получить один элемент из поля tableRecord.Data
, было бы изменить тип поля на то, чем оно является на самом деле:
type tableRecord struct {
PrimaryKey string
Data []interface{} // slice of whatever
}
Таким образом, вы можете написать что-то очень общее:
for tbl, record := range records {
fmt.Printf("First record from table %s\n", tbl)
b, _ := json.MarshalIndent(record[0], " ", " ")
fmt.Println(string(b))
fmt.Prinln("other records...")
b, _ = json.MarshalIndend(record[1:], " ", " ")
fmt.Println(string(b))
}
Однако, я бы подумал о том, чтобы реализовать интерфейс в моих типах БД.Что-то вроде:
type DBType interface {
PrimaryKey() string
TableName() string // xorm can use this to get the table name
Slice() []DBType // can return []user or whatever
}
Так что вам больше не нужен тип tableRecord
, и вы можете просто использовать переменную, подобную этой:
listOfTables := []DBType{user{}, ...}
for _, tbl := range listOfTables {
data := tbl.Slice()
// find data here
fmt.Printf("First record from table %s\n", tbl.TableName())
b, _ := json.MarshalIndent(data[0], " ", " ")
fmt.Println(string(b))
fmt.Prinln("other records...")
b, _ = json.MarshalIndend(data[1:], " ", " ")
fmt.Println(string(b))
}
Так что TL; DR того, чего не хватало в моем ответе / комментариях:
Приведение типа []user{}
(или []DBTable
) к []interface{}
не работает, видякак вы не можете привести все элементы в срез в одном выражении.Вам нужно будет создать второй фрагмент типа []interface{}
и скопировать значения следующим образом:
slice: = userVar.Slice () data: = make ([] interface {}, len (slice))) для i: = диапазон slice {data [i] = slice [i] // копировать тип в интерфейс {} slice} вернуть tableRecord {userVar.PrimaryKey (), data}
Я создал небольшой рабочий пример того, как вы можете использовать интерфейсы, как описано выше.
Чтобы избежать слишком большого количества беспорядка, вы можете изменить функцию Slice
, чтобы вернуть []interface{}
сразу же:
func(v T) Slice() []interface{
return []interface{
&T{},
}
}
Что было не так с вашей реализацией Slice
, так это то, что у вас было что-то вроде этого:
func (u *user) Slice() []DBTable {
u = &user{} // you're re-assigning the receiver, losing all state!
return []DBTable{u}
}
Получатель имеет тип указателя, поэтому любые переназначения, которые вы делаете, будут влиять на переменнуюна котором был назван func.Это не очень хорошая идея.Просто используйте получатели значений или, если вы хотите быть уверены, что интерфейс реализован только для переменных-указателей (обычная уловка, используемая, например, gRPC), заключается в реализации функции следующим образом:
func(*user) Slice() []DBTable{
return []DBTable{&user{}}
}
Хороший пример этого трюка можно найти в сгенерированных pb.go
файлах при использовании буферов протокола.Типы сообщений будут иметь такую функцию:
func(*MsgType) ProtoMessage() {}