Golang get a string name of struct field - go

I would like to get the string name of a field like it is possible to do in C#:
if (x == null)
throw new ArgumentNullException(nameof(x));
In GO I have the following:
package main
type Test struct{
X int
Y string
}
func main() {
fmt.Println(nameof(Test.X))
}
How I can implement the nameof func?

How I can implement nameof func?
You cannot.
Fortunately you need not. While writing the code you know the name and can type the string literal as fast as nameof().
(Okay, you technically can, by inspecting the current function an looking up debug symbols but this is complicated and probably non-portable and dependent on the compiler version used. So: Don't even try.)

Lets say you have this struct
type User struct{
Id string
Name string
// etc
}
Then you can have something like this:
query := fmt.Sprintf("select * from Users where %s like %s", nameof(User.Name), "foo")
obviously in go the nameof function does not exists. You could replace that with reflect.TypeOf(User.Name).Name()
That is helpful because if you where to modify your database and replace Name with FirstName and LastName then your code will no longer compile.

Related

Is there a way we can ensure passed values have certain fields using generics?

I am trying to define a generic function in Go that accepts values that have certain fields, for example, ID int. I have tried several approaches but none seems to work. Here is an example of what I have tried.
package main
import (
"fmt"
)
func Print[T IDer](s T) {
fmt.Print(s.ID)
}
func main() {
Print(Person{3, "Test"})
}
type IDer interface {
~struct{ ID int }
}
type Person struct {
ID int
Name string
}
type Store struct {
ID int
Domain string
}
And here is the playground link: https://gotipplay.golang.org/p/2I4RsUCwagF
In the example above, I want to guarantee every value passed to the Print function has a property ID int, which is also accessible in the function. Is there any way I can achieve this is Go without defining a method in an interface (e.g., GetID() int)?
Is there any way I can achieve this is Go without defining a method in an interface (e.g., GetID() int)?
No, you have to define the method in an interface.
The generics implementation in Go 1.18 doesn't have support for structural types, even though the original type parameters proposal suggests it would. For accessing common fields in a union instead see also this explanation.
Although, I think it's worth it to point out a misconception that can easily arise from your example: the meaning of the approximation ~T (tilde-type) means "the set of types whose underlying type is T.
Now, when you write:
~struct{ ID int }
this means types whose underlying type is exactly struct{ ID int }. No matter what, this does not include structs that have the field ID int and something else. E.g. the underlying type of type Foo struct { ID int; Name string } is struct { ID int; Name string }, and not struct{ ID int }, so that wouldn't satisfy the constraint anyway.
The current time param implementation doesn't have syntax to specify partial struct types. I recall a proposal to add field terms in interface constraints (along with type terms and methods), something on the line:
type IDer interface {
ID int
}
which would enable what you are trying to do without breaking the meaning of the tilde ~. But this won't be included in Go 1.18.

Reflection to get field tag

In Go is there a good way to use reflection to get a field tag by just wrapping a field in a function from the reflect library?
I am basically trying to create a thin data access object that allows be to get the column name in the db without hard coding it all over the place.
Below is the struct with db column names as tags.
// Table Structures
type CusipTableRow struct {
Id int64 `db:"id"`
Cusip string `db:"cusip"`
Symbol string `db:"symbol"`
Active int8 `db:"active"`
Added_Time int32 `db:"added_timestamp"`
Description string `db:"description"`
Exchange string `db:"exchange"`
AssetType string `db:"asset_type"`
}
I am seeking a suggestion other than downloading another library on how to use reflection to essentially make a call like this to return a string with the tag value.
var row CusipTableRow
row.GetColumnName(row.Id) //Return column name based on tag.
I was considering possibly trying to use a map[address] fieldTag, but did not have luck getting that to work perhaps due to not fully having a grasp of the unsafe package. If that approach would have worked I was thinking a call like this could have worked:
row.GetColumnName(&row.Id) //Return column name based on tag.
You can get field tag given the address of the struct and the address of the field. Unsafe shenanigans are not required.
func GetColumnName(pstruct interface{}, pfield interface{}) string {
v := reflect.ValueOf(pstruct).Elem()
for i := 0; i < v.NumField(); i++ {
if v.Field(i).Addr().Interface() == pfield {
return v.Type().Field(i).Tag.Get("db")
}
}
panic("field not in struct")
}
Example use:
var v CusipTableRow
fmt.Println(GetColumnName(&v, &v.Added_Time)) // prints added_timestamp
Run it on the Go Playground.

Why must I pass type to make function when variable is already declared?

I want use anonymous struct to do something.
var users []struct{
Name string `json:"name,omitempty"`
Age int
}
and I have to write the type again to set value
users = make([]struct{
Name string `json:"name,omitempty"`
Age int
}, 0, 10)
if I insist using anonymous struct, is there any way to make it more decent?
(if no, I wonder why golang design make function like this...)
Anonymous structs are handy for one-time use.
If you are using it more than once, then define a named struct type.
If you only use it within a single function, you can define the type within the scope of that particular function, so it's obvious that it cannot be used elsewhere:
func myfunc() {
type MyType struct {
Name string
}
m := MyType{Name: "Hello, World!"} // this type can only be used within this func
fmt.Println(m)
}
if I insist using anonymous struct, is there any way to make it more decent?
Yes, there is. Use :=:
users := make([]struct{
Name string `json:"name,omitempty"`
Age int
}, 0, 10)
Of course, this only works if you're calling make right after you're defining the variable. If these bits are separated by other code, this trick won't work for you.
But don't be afraid to name your types. That's generally a better approach anyway (with or without :=).

Why does golang prohibit assignment to same underlying type when one is a native type?

Consider this code:
package main
import "fmt"
type specialString string
func printString(s string) {
fmt.Println(s)
}
// unlike, say, C++, this is not legal GO, because it redeclares printString
//func printString(s specialString) {
// fmt.Println("Special: " + s)
//}
func main() {
ss := specialString("cheese")
// ... so then why shouldn't this be allowed?
printString(ss)
}
My question is: why is the language defined so that the call to printString(ss) in main() is not allowed? (I'm not looking for answers that point to the Golang rules on assignment; I have already read them, and I see that both specialString and string have the same 'underlying type' and both types are 'named' -- if you consider the generic type 'string' to be named, which Golang apparently does -- and so they are not assignable under the rules.)
But why are the rules like that? What problem is solved by treating the built-in types as 'named' types, and preventing you from passing named types to all the standard library functions that accepting the same underlying built-in type? Does anybody know what the language designers had in mind here?
From my point of view, it seems to create a lot of pointless type conversion in the code, and discourages the use of strong typing where it actually would make sense..
I believe the initial authors' logic here is that named type is named for a reason - it represents something different, not just underlying type.
I guess I've read it somewhere in golang-nuts, but can't remember exact discussion.
Consider the following example:
type Email string
You named it Email, because you need to represent e-mail entity, and 'string' is just simplified representation of it, sufficient for the very start. But later, you may want to change Email to something more complex, like:
type Email struct {
Address string
Name string
Surname string
}
And that will break all your code that work with Email implicitly assuming it's a string.
This is because Go does not have class inheritance. It uses struct composition instead. Named types do not inherit properties from their underlying type (that's why it's not called "base type").
So when you declare a named type specialString with an underlying type of a predefined type string, your new type is a completely different type from the underlying one. This is because Go assumes you will want to assign different behaviors to your new type, and will not check its underlying type until run-time. This is why Go is both a static and dynamic language.
When you print
fmt.Println(reflect.TypeOf(ss)) // specialString
You get specialString, not string. If you take a look at Println() the definition is as follows:
func Println(a ...interface{}) (n int, err error) {
return Fprintln(os.Stdout, a...)
}
This means you can print any predeclared types (int, float64, string) because all of them implements at least zero methods, which makes them already conform to the empty interface and pass as "printable", but not your named type specialString which remains unknown to Go during compile time. We can check by printing the type of our interface{} against specialString.
type specialString string
type anything interface{}
s := string("cheese")
ss := specialString("special cheese")
at := anything("any cheese")
fmt.Println(reflect.TypeOf(ss)) // specialString
fmt.Println(reflect.TypeOf(s)) // string
fmt.Println(reflect.TypeOf(at)) // Wow, this is also string!
You can see that specialString keeps being naughty to its identity. Now, see how it does when passed into a function at run-time
func printAnything(i interface{}) {
fmt.Println(i)
}
fmt.Println(ss.(interface{})) // Compile error! ss isn't interface{} but
printAnything(ss) // prints "special cheese" alright
ss has become passable as interface{} to the function. By that time Go has already made ss an interface{}.
If you really want to understand deep down the hood this article on interfaces is really priceless.
It's called nominal typing. It simply means that the type is identified by it's name and it has to be made explicit to be useful.
From a convenience point of view it is easy to critique but it super useful.
For example, let's say you have a parameter to a function that is a string but it cannot be just any string, there are rules you need to check. If you change the type from string to something that implies that you checked the string for potential problems you made a good design decision because it's now clear from just looking at the code that the string needs to go via some function to validate the input first (and enrich it's type in the process).
type Validated string
func Validate(input string): (Validated, err) {
return Validated(input), nil // assuming you actually did validate the string
}
Go makes these tradeoffs because it does improve readability (i.e. the ability of someone unfamiliar with your code to quickly understand how things work) and that's something they (the Go language designers) value above all else.

Instantiating a struct via name using a string in go

I am trying to create a function that takes a []byte and an interface{} (standing for the struct) and returns an interface{} as the struct type passed into the func.
Something like this:
package main
import (
"encoding/json"
)
func UnmarshalFromJSONArray(sms []byte,tt string) (interface{}) {
var ts = new(tt)
err := json.Unmarshal(sms,&ts)
if(err != nil) {
fmt.Println(err)
}
return sms
}
So that method would run something like this:
// let's say a struct has the following definition:
type MyStructType struct {
Id int
Name string
Desc string
}
// we can some how get its fully qualified class name (this may require reflection?) or pass it into the UnMarshal method direction some how.
mst := "package.MyStructType",
// and then assume a byte array ba that has JSON format for
ba := []byte(`{"Id":"3","Name":"Jack","Desc":"the man"}`)
stct := UnmarshalFromJSONArray(ba,mst)
MyStructureType out := stct
// leaving "stct" being the unmarshalled byte array which can be used like any other struct of type "MyStructureType"
The key being that I never need to know what the fields of MyStructureType are before unmarshalling. All I need are the name of the struct and some way to instance one and then populate it with JSON byte array data that matches its fields. Hopefully that is possible (it is trivial in java using reflection). So I want to basically unmarshal an anonymous struct type by it's name without needing to know what fields it has.
Any suggestions?
The short answer is that this is impossible. There is no string to type translator in Go. You can make a map of strings to reflect.Type's, but you would need to know the possible options ahead of time or you need to provide the caller with a way to register types (perhaps in init).
Assuming you have found a way to resolve the string to its reflect.Type, you can simply call reflect.New(typ).Interface() to get the pointer you need to pass to json.Unmarshal().
The best answer is to avoid trying this all together. Writing idiomatic Java in Go isn't really possible. If I knew more about your problem, I could give you a more idiomatic Go solution.

Resources