-2

I am working on a demo project to understand GO language. I have defined one interface and 2 struct type. Also, I have defined an array of interfaces. Depending on the user input, I define each element within the array as a type of struct. During the data manipulation, I want to check the type of the struct defined on the array.

I have tried to use reflect, but unfortunately it did not worked. Also other methods on internet did not worked. I received messages such as panic or json cannot Unmarshal.

type Main_interface interface {
}

type Struct1 struct {
    Index                         int
    ID                            int
    Name                          string
}

type Struct2 struct {
    Index                         int
    Timestamp                     string
    Temporary_ID                  int
}


var MyArray []Main_interface

//...
NewStruct1Block := generateStruct1Block(...)
MyArray = append(MyArray, NewStruct1Block)

//...
NewStruct2Block := generateStruct2Block(...)
MyArray = append(MyArray, NewStruct2Block)

UPDATE: I want to be able to check the kind of struct implements the interface at runtime, depending on the user input.

Liviu
  • 15
  • 1
  • it's not clear what error you are encountering or exactly what you are trying to do. See this answer https://stackoverflow.com/questions/38816843/explain-type-assertions-in-go and this tour of go section https://tour.golang.org/methods/15 for the basics of type assertions - maybe this is what you are looking for? – Vorsprung Jan 15 '19 at 12:01
  • 1
    Probably the best advice here would be: Do not try to understand what's going on using reflection. Reflection is _hard_. It is hard even if you _do_ know the language and how interfaces and the type system work. Trying to increase your understanding of the type system by use of reflection is doomed to fail. – Volker Jan 15 '19 at 12:33
  • If you tried something and it didn't work, please include that code in the body of your question, along with details on the way in which it didn't work. – Adrian Jan 15 '19 at 14:17
  • I tried both solutions described below. I initialize the first element of the array in main through hard coding. The type test works fine for this element. The rest of the elements are initialized depending on the user input, and the type of the elements returned is the interface type. I do not want this. I want the return Struct1 or Struct2. – Liviu Jan 15 '19 at 14:33
  • 1
    Ok, answer to your question is `type assestion`. It is not really possible to provide you with a fully working application (and this resource is not intended for such purpose) without knowing your particular requirements as currently they look bit confusing. – P.An Jan 15 '19 at 14:44

2 Answers2

5

Your array can be heteregenious, that is, it can contain elements of different types. You can't ensure (at compile time) that all elements are of the same type.

That said, you can check a single element using the type cast syntax.

You have three options:

Option 1: Check against a specific type

var unknown Main_Interface = getSomethingSomewhere()
result, ok := unknown.(Struct1);
if ok {
    // result has type `Struct1` 
}

Option 2: Use a switch statement to cover multiple types (already presented in another answer)

switch t := unknown.(type) {
case Struct1:
    // t has type `Struct1` within this block (at compile time)
case Struct2:
    // t has type `Struct2` within this block (at compile time)
default:
    // neither Struct1 no Struct2
}

Option 3: compare against another type at runtime.

Note that types returned by reflect.TypeOf are comparable using the == operator, as documented here:

https://golang.org/pkg/reflect/#Type

Type values are comparable, such as with the == operator, so they can be used as map keys. Two Type values are equal if they represent identical types.

So we can do something like this:

var s1 Struct1 // empty struct
var s2 Struct2 // empty struct
if reflect.TypeOf(unknown) == reflect.TypeOf(s1) {
    // unknown holds an s1 instance
}

But this is obviously not useful when you can just do the compile time check. Instead, you can compare two unknowns to check if they are the same:

var unknown1 Main_Interface = getSomethingSomewhere()
var unknown2 Main_Interface = getSomethingSomewhereElse()

if reflect.TypeOf(unknown1) == reflect.TypeOf(unknown2) {
    // they are the same type
}
Gavin
  • 4,365
  • 1
  • 18
  • 27
user10753492
  • 720
  • 4
  • 8
  • 1
    Just for clarity, option 1 is a type *assertion*, not a type *cast*: https://golang.org/ref/spec#Type_assertions – Adrian Jan 15 '19 at 14:18
  • Those solutions work fine only for the first element of the array which I initialize in main, through hard coding. The rest of the elements are returned as the main interface. – Liviu Jan 15 '19 at 14:26
  • @Liviu if this doesn't answer your question, then I don't understand your question. Maybe you can clarify it better? – user10753492 Jan 16 '19 at 01:22
1

You need to use type assestion as below:

var MyArray []Main_interface

NewStruct1Block := Struct1{}
NewStruct2Block := Struct2{}

MyArray = append(MyArray, NewStruct1Block)
MyArray = append(MyArray, NewStruct2Block)

fmt.Printf("%v", MyArray)

switch t := MyArray[0].(type) {
case Struct1:
    fmt.Printf("%v", t)
    t.ID = 1
case Struct2:
    fmt.Printf("%v", t)
    t.Timestamp = "A"
default:
    fmt.Print("unknown")
}

Working code here: https://play.golang.org/p/OhpBDJu_q2x

P.An
  • 355
  • 1
  • 9
  • Unfortunately this solution returns Main_interface type. I want to return Struct1 type or Struct2 type, even is I append only Struct1 or Struct1 types – Liviu Jan 15 '19 at 13:48
  • Are you sure about that? This solution doesn't return a type at all, it prints the *value* if the type is `Struct1` or `Struct2`, otherwise it prints `unknown`. – Adrian Jan 15 '19 at 14:19
  • No it does not. Please check the updated code in playground: you can assign struct values to `t` – P.An Jan 15 '19 at 14:21
  • This solution works fine only for the first element of the array which I initialize in main, through hard coding. The rest of the elements are returned as the main interface. – Liviu Jan 15 '19 at 14:25