2016-08-25 4 views
3

У меня есть несколько различных структур, как Big с Small вставленных в смещении 0. Как я могу получить доступ к Small «s структурам поля из кода, который ничего не знает о Big типа, но известно, что Small находится со смещением 0?Golang: преобразовать в-структуру вкладываются в смещении 0-структуры

type Small struct { 
    val int 
} 

type Big struct { 
    Small 
    bigval int 
} 

var v interface{} = Big{} 
// here i only know about 'Small' struct and i know that it is at the begining of variable 
v.(Small).val // compile error 

Кажется, что компилятор теоретически может работать такое выражение, потому что он знает, что Big типа имеет Small типа встроенный со смещением 0. Есть ли способ сделать такие вещи (возможно, с unsafe.Pointer)?

+0

игнор - не реальный вопрос правильно – Sridhar

ответ

1

Хотя ответ с отражением работает, но он имеет штрафные санкции и не является идиоматическим для Go.

Я считаю, что вы должны использовать интерфейс. Как это

https://play.golang.org/p/OG1MPHjDlQ

package main 

import (
    "fmt" 
) 

type MySmall interface { 
    SmallVal() int 
} 

type Small struct { 
    val int 
} 

func (v Small) SmallVal() int { 
    return v.val 
} 

type Big struct { 
    Small 
    bigval int 
} 

func main() { 
    var v interface{} = Big{Small{val: 3}, 4} 
    fmt.Printf("Small val: %v", v.(MySmall).SmallVal()) 
} 

Выход:

Small val: 3 
+1

это нормально для меня, спасибо – Exel

1

Избегайте использования unsafe, когда это возможно. Выше задача может быть выполнена с использованием отражения (reflect пакета):

var v interface{} = Big{Small{1}, 2} 

rf := reflect.ValueOf(v) 
s := rf.FieldByName("Small").Interface() 

fmt.Printf("%#v\n", s) 
fmt.Printf("%#v\n", s.(Small).val) 

Output (попробовать его на Go Playground):

main.Small{val:1} 
1 

Примечание:

Это работает для любого поля, а не только первый (при «смещении 0»). Это также работает и для именованных полей, а не только для встроенных полей. Однако это не работает для неэкспортированных полей.

+0

почему бы не просто бросить в Большой, а затем принять v.val или v.Small.val ? Отражение здесь излишнее, не так ли? –

+0

@AlexanderTrakhimenok Asker хочет, чтобы мы не знали о 'Big'. Преобразование или извлечение значения типа «Большой» не подходит для этого. – icza

1
type Small struct { 
    val int 
} 

type Big struct { 
    Small 
    bigval int 
} 

func main() { 
    var v = Big{Small{10},200} 
    print(v.val) 
} 
+0

Но переменная 'v' от пользователя имеет тип' interface {} ', ваш тип' Big'. – icza

+0

Ops! Я читал неправильно! В этом случае ваш ответ правильный! – gianlucatursi