2016-04-06 3 views
2

У меня есть функция, которая выглядит следующим образом:Go: Передача возвращаемого значения через интерфейс {} указатель

func Foo(result interface{}) error { 
    ... 
    json.Unmarshal([]byte(some_string), result) 
    ... 
} 

, который называется так:

var bar Bar 
Foo(&bar) 

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

type Loader func() (interface{}) 

func Foo(result interface{}, Loader load) error { 
    ... 
    data := load() 
    // result = data ??? 
    ... 
} 

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

+0

Первая версия Foo не работает. Unmarshal, чтобы результат, а не указатель на результат. 'json.Unmarshal ([] byte (some_string), result)'. –

ответ

5

Вы можете сделать,

p := result.(*Bar) 
*p = data 

Первая строка является type assertion.

Второе присваивает data указателю с разыменованием. Присвоение значения разыменованному указателю изменяет значение на указанном адресе.

Поскольку вы не знаете базовые типы result или data, то лучше всего использовать переключатель утверждения типа.

switch v := data.(type) { 
case Bar: 
    // If 'data' is of type 'Bar' 
    p, ok := result.(*Bar) 
    if(!ok){ 
     // This means inputs were bad. 
     // 'result' and 'data' should both have the same underlying type. 
     fmt.Println("underlying types mismatch") 
     break; 
    } 

    *p = v 

case Baz: 
    // If 'data' is of type 'Baz' 
    // Equivalent of above for 'Baz' 
} 

См Тип Переключатели от switch statement

+0

Проблема только в том, что я не знаю конкретного типа результата внутри Foo. Вот почему я использую интерфейс {}. Нужно ли использовать рефлектор, чтобы понять это? – Bill

+0

Билл, извините, я пропустил это. Обновленный ответ с лучшим решением, которое я мог бы придумать. Надеюсь, вы продумали этот API. Может быть, вы можете изменить его, чтобы просто вернуть данные вместо назначения его указателю? –

+0

Мне нужно передать ссылочную структуру для случая десериализации в любом случае и независимо от того, как я рефакторинг, я всегда собираюсь дойти до точки, где я либо загружаю структуру, либо десериализую строку. В результате он становится чем-то вроде foo (result interface {}, load Loader) (интерфейс {}, ошибка), который хорош, но не так чист, как я надеялся. – Bill

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