2016-04-07 2 views
0

Здесь находится игровая площадка https://play.golang.org/p/qMKxqrOcc2. Проблема аналогична проблеме, которая находится на игровой площадке.Как определить динамическую структуру типа в golang?

Скажем, у меня есть условие, и нужно сделать это:

if modelName == "a"{ 
    model = models.A 
} 
else{ 
    model = models.B 
} 

где A и B некоторые модели:

type A struct{ 
    filed1 string 
    field2 string 
    //etc 

} 

и модель B является

type B struct{ 
    filed1 string 
    field2 string 
    //etc 

} 

Поля в A и B га s одни и те же поля, но в основном они отражают таблицу базы данных (документ), и они имеют один и тот же тип (тип struct).

Когда я говорю, перед всем, что:

var model interface{} 

я получил ошибку:

type models.A is not an expression 

Я делаю это, чтобы избежать дублирования кода в коде, если вы спрашиваете, почему.

Вопрос похож на это: How to return dynamic type struct in Golang?

Вот обновление для кода:

b := c.mainHelper.GetModelBy("id", id, modelName).(map[string]interface{}) 
mapstructure.Decode(b, &model) 

if modelName == "a"{ 
    model.Photos = []string{"ph1","ph2"} 
} 
if modelName == "b"{ 
    model.Docs = []string{"doc1","doc2"} 
} 

c.mainHelper.UpdateModel(product, id, modelName) 

Я знаю, что это глупо, и, вероятно, это невозможно сделать, но есть и способ сделать это:

var model models.modelName --> somehow to concat modelName to this models? 

ЗДЕСЬ NEW UPDATE

У меня есть две модели почты и продукта. У обоих из них есть поле «Фотографии».

type Post struct{ 

    Photos []string 
    //etc 
} 

type Product { 

    Photos []string 
    // 
} 

Теперь я нужна одна функция, которая будет сказать:

func() RemovePhotos(id string, modelName string){ 

//if modelName=="post" 
    //get model post with id 

//if modelName=="product" 
    //get model product with id 

//set model.Photos = []string 
//update model in db 
} 

Я могу понять, что я не могу назначить тип, но, как использовать эту одну функцию, чтобы удалить данные из типов различно? Насколько я могу видеть, избыточный код будет выглядеть следующим образом:

func() RemovePhotos(id string, modelName string) return bool{ 

    if modelName == "post"{ 

     var model models.Post 
     modelWithdata := getModelWithId.(*model) 
     modelWithdata.Photos = []string 
     //update model in db here 
    } 
    if modelName == "product"{ 
     var model models.Product 
     modelWithdata := getModelWithId.(*model) 
     modelWithdata.Photos = []string 
     //update model in db here 
    } 

    //it does not matter what I return this is just redundancy example 
    return true 

} 

Как вы можете только разница в том, вар модель models.Post/var model models.Product. Это избыточность в коде, и это выглядит уродливым, но если нет никакого способа обойти это, тогда хорошо, у меня будет этот законченный с избыточностью.

+0

Как «модель» будет использоваться после назначения? Лучшее решение будет зависеть от этого. –

+5

«Я делаю это, чтобы избежать избыточности кода». Не делай этого слишком рано! Не избегайте избыточности, пока не увидите, что действительно избыточно и может быть учтено в (непустом) интерфейсе. Тогда вы избегаете избыточности. – Volker

+0

Я не могу принять никакого ответа, так как они не дают достаточного количества ответов. Я попробовал все это от ответов, прежде чем задал мне вопрос. – pregmatch

ответ

0

Это ваша программа от редактирования с реализацией типа интерфейса:

package main 

import (
    "log" 
) 

//// Interfaces //// 
type PhotoManager interface { 
    AddPhotos(id string) (bool, error) 
} 

//// Post //// 
type Post struct { 
    Photos []string 
} 

func (p *Post) AddPhotos(id string) (bool, error) { 
    p.Photos = append(p.Photos, id) 
    return true, nil 
} 

//// Product //// 
type Product struct { 
    Photos []string 
    Docs []string 
} 

func (p *Product) AddPhotos(id string) (bool, error) { 
    p.Photos = append(p.Photos, id) 
    return true, nil 
} 

// Useless function to demonstrate interface usage // 
func AddPhotoToInterfaceImplementation(id string, pm PhotoManager) { 
    pm.AddPhotos(id) 
} 

//// Main //// 
func main() { 
    post := Post{} 
    product := Product{} 
    post.AddPhotos("123") 
    product.AddPhotos("321") 
    AddPhotoToInterfaceImplementation("456", &post) 
    AddPhotoToInterfaceImplementation("654", &product) 
    log.Println(post) 
    log.Println(product) 
} 

Подвижные части здесь являются:

  • типа PhotoManager interface, который используется для определения интерфейса с родовыми функциями
  • реализации AddPhotos на Post и Product для обеспечения фактических реализаций функций интерфейса
  • использование pm PhotoManager в качестве параметра для AddPhotoToInterfaceImplementation, чтобы показать использование типа интерфейса.
5

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

package main 

import "fmt" 

type B struct { 
    filed1 string 
    field2 string 
    //etc 

} 

type A struct { 
    filed1 string 
    field2 string 
    //etc 

} 

func main() { 
    var model interface{} 
    modelName := "b" 
    if modelName == "a" { 
     model = A{} // note the {} here 
    } else { 
     model = B{} // same here 
    } 

    fmt.Println(model) 
} 

Просто слово советы, хотя, вероятно, вы не хотите использовать общий interface{} тип, а его лучше использовать фактический интерфейс, что оба A и B орудия. Общий тип интерфейса вызовет у вас больше головных болей и действительно победит цель использования статически типизированного языка, такого как Go.

+3

Чтобы предотвратить использование интерфейса {}, вы можете посмотреть [интерфейсы] (http://jordanorelli.com/post/32665860244/how-to-use-interfaces-in-go) (sic) – RickyA

+0

@RickyA Согласовано но на основе вопроса, который он задает о назначении конкретной модели, а не определении поведения. Конечно, поведение также может быть добавлено к самим моделям, чтобы избежать этих проблем, но это действительно зависит от случая использования афер. –

+0

true, я просто добавил этот комментарий, потому что интерфейс является единственным способом обобщения типов без отражения с помощью 'interface {}'. Если он строит завод, он может помочь ему. – RickyA

2

Вы получаете ошибку, потому что пытаетесь присвоить тип экземпляру interface{}. Вам нужно назначить экземпляр.

Если у вас это было;

var model interafce{} 

if modelName == "a"{ 
    model = models.A{} 
} 
else{ 
    model = models.B{} 
} 

тогда это будет работать нормально.

+0

это не работает, потому что при попытке сделать что-то вроде model.SomeFiled = "somevalue" он говорит, что интерфейс типа {} не имеет поля или метода SomeFiled – pregmatch

+0

@pregmatch yes 'interface {}' является самым общим типом в Go, это doesn 't выставлять любые поля или методы из базового типа. Вы должны сделать утверждение типа типа 'typeA: = interfaceInstance.(A) 'для доступа к полям на' A' – evanmcdonnal

+0

@pregmatch, как это обычно обрабатывается, было бы, чтобы ваш метод доступа db возвращал 'interface {}', а затем использовал переключатель типа в области вызова для ' unbox 'значение. – evanmcdonnal

Смежные вопросы