29

ERROR: type CustomStruct is not an expression.

type CustomStruct struct {
}

func getTypeName(t interface{}) string {
    rt := reflect.TypeOf(t).Elem()
    return rt.Name()
}

getTypeName(CustomStruct)

How can I pass struct type to function without type instance?

This will work

getTypeName((*CustomStruct)(nil))

But I wonder if there is more simple version..

Ali Padida
  • 1,763
  • 1
  • 16
  • 34
Lion.k
  • 2,519
  • 8
  • 28
  • 43
  • Using `reflect.Type`. – thwd Jun 29 '18 at 08:16
  • 2
    Just curious, but _why_ would you want to get the type of a name at runtime? If it's just for output, you could just use `fmt.Sprintf` with the golang format: `fmt.Printf("%#v", var)` which would print out something like `main.CustomStruct{}` (type + value) – Elias Van Ootegem Jun 29 '18 at 10:10
  • 4
    This really sounds like an XY Problem. Why do you want to do this? – Jonathan Hall Jun 29 '18 at 10:21

3 Answers3

39

You can't. You can only pass a value, and CustomStruct is not a value but a type. Using a type identifier is a compile-time error.

Usually when a "type" is to be passed, you pass a reflect.Type value which describes the type. This is what you "create" inside your getTypeName(), but then the getTypeName() will have little left to do:

func getTypeName(t reflect.Type) string {
    return t.Name()
}

// Calling it:
getTypeName(reflect.TypeOf(CustomStruct{}))

(Also don't forget that this returns an empty string for anonymous types such as []int.)

Another way is to pass a "typed" nil pointer value as you did, but again, you can just as well use a typed nil value to create the reflect.Type too, without creating a value of the type in question, like this:

t := reflect.TypeOf((*CustomStruct)(nil)).Elem()
fmt.Println(t.Name()) // Prints CustomStruct
icza
  • 389,944
  • 63
  • 907
  • 827
  • I already mentioned like this, getTypeName((*CustomStruct)(nil)) – Lion.k Jun 29 '18 at 08:22
  • 3
    @yountae.kang Yes, I know and I referred to it (_"as you did"_). There is no other way, you can't pass a type identifier, that's not a value. – icza Jun 29 '18 at 08:23
  • How do I instantiate CustomStruct using t in the implementation of the the function? –  Jul 05 '20 at 07:56
  • @QianChen E.g. `reflect.New(t)`, it returns you a pointer to `CustomString` wrapped in `reflect.Value`. – icza Jul 06 '20 at 07:47
  • @QianChen, a bit after the fact, but if you're still looking, given a type T, 'reflect.New(T).Type().Elem()' gives you a reflect.Type for T – Sam Hughes Jun 23 '21 at 04:59
  • Let's say that rather than a Generic I DO want to pass a type. How would I go about passing an int type? using reflect.TypeOf(int) doesn't do it, but reflect.TypeOf(0) does. – Lord of Scripts Aug 02 '23 at 23:27
7

Lets resurrect this!

The generics proposal for Go got approved, and that's coming, eventually. When this question was first asked, this probably made more sense as a question, but for anyone looking to implement a generics pattern now, I think I've got an alright API for it.

For now, you can't interact with abstract types, but you can interact with methods on the abstract type, and reflect allows you to examine function signatures. For a method, the 0th is the receiver.

type Example struct {int}
type Generic struct{reflect.Type}

func (p Example) Type() {}

func Reflect(generic interface{}) Generic {
    real := reflect.TypeOf(generic)
    if real.Kind() != reflect.Func || real.NumIn() < 1 {
        panic("reflect.Type.In(n) panics if not a func and if n out of bounds")
    }
    return Generic{real.In(0)}
}

func (g Generic) Make() interface{} {
    return reflect.Zero(g.Type).Interface()
}

func main() {
    tOfp := Reflect(Example.Type)
    fmt.Printf("Name of the type: %v\n", tOfp.Name()) 
    fmt.Printf("Real (initial)value: %v\n", tOfp.Make())
}

Some quick notes:

  1. The structure of "Example" doesn't matter, rather only that it has a method with a non-pointer receiver.
  2. The definition of a type called "Generic" as a struct is to accomplish what I believed OP's actual intent to be.
  3. The above definition of "Generic" is a struct instead of an interface so that it can have its own method set. Defining "Generic" as an interface, and using a methodset specific to each operand-type used with it would make tons of sense.

If you weren't aware, actual generics are coming in Go 1.18. My example above has no linter or compile protection, and will panic at runtime if used incorrectly. It does work, and will let you reason over abstract types while you wait for a native implementation.

Happy Coding!

Sam Hughes
  • 665
  • 8
  • 10
  • omg, this seems to work even if I make parent/base struct for Example and define Type method there. much more close to java like virtual inheritance. need more experiments, but promising, thanks! – Павел Jun 08 '23 at 04:43
3

From Go version 1.18 a new feature Generics has been introduced. In most of the case instead of passing types to function, we can use generics. Then we will also get compile time error instead of runtime error and it's more efficient than reflect also.

Example Code

func HttpGet[T](url, body) T {
    var resp T
    return T
}

resp := HttpGet[ResponseType]("dummy.example", nil)
Shahriar Ahmed
  • 502
  • 4
  • 11