Golang embedded `time.Time` printed over other fields - go

I'm a new starter in Go. Here is a problem that has been puzzling me.
In short, when I printed a struct with an anonymous field of the type time.Time, the output was similar to a time.Time variable printed alone. Neither braces nor other fields were displayed.
package main
import (
"fmt"
"time"
)
type Embedding struct {
i int
time.Time
}
type NoEmbedding struct {
i int
Present time.Time
}
func main() {
// `embedding` and `noEmbedding` shared exactly the same content
embedding := Embedding{
1,
time.Now(),
}
noEmbedding := NoEmbedding{
1,
time.Now(),
}
fmt.Println("embedding:\n", embedding)
fmt.Println("no embedding:\n", noEmbedding)
}
/* output
embedding:
2020-09-18 01:42:37.9201284 +0800 CST m=+0.011626601
no embedding:
{1 2020-09-18 01:42:37.9201284 +0800 CST m=+0.011626601}
*/
The problem is essentially a further step into "Why is time in Go printed differently in a struct?" I've gone over "Embedding in GO" but yet to find any clues.

fmt.Println will use the String method if one exists. When you embed a time value in a struct, the String method of Time is promoted to struct's String method. That's the reason why it prints differently.

Related

Unmarshal into pointer vs value receiver feilds [duplicate]

This question already has answers here:
Difference using pointer in struct fields
(3 answers)
Closed 3 years ago.
I'm learning Golang recently. I know pointer and value receivers how it works generally.
When Unmarshal JSON string like follow 2 examples, I feel that first one (pointer receiver) more efficient way to use memory. But I have seen lots of examples and articles not uses this way. Is there any reason for this? And what are use cases for them?
package main
import (
"encoding/json"
"fmt"
)
type Outer struct {
ID int `json:"id"`
PointerValue *string `json:"pointer_str"`
Inner *Inner `json:"inner"`
}
type Inner struct {
Value string `json:"value"`
}
func main() {
testJson := `{
"id": 1,
"pointer_str": "example-value",
"inner": {
"value": "some-value"
}
}`
testStruct := &Outer{}
json.Unmarshal([]byte(testJson), testStruct)
fmt.Printf("%+v\n", testStruct)
fmt.Printf("%+v\n", *testStruct.PointerValue)
fmt.Printf("%+v\n", testStruct.Inner)
}
Output:
&{ID:1 PointerValue:0x40c250 Inner:0x40c258}
example-value
&{Value:some-value}
Or
package main
import (
"encoding/json"
"fmt"
)
type Outer struct {
ID int `json:"id"`
PointerValue string `json:"pointer_str"`
Inner Inner `json:"inner"`
}
type Inner struct {
Value string `json:"value"`
}
func main() {
testJson := `{
"id": 1,
"pointer_str": "example-value",
"inner": {
"value": "some-value"
}
}`
testStruct := &Outer{}
json.Unmarshal([]byte(testJson), testStruct)
fmt.Printf("%+v\n", testStruct)
fmt.Printf("%+v\n", testStruct.Inner)
}
Output:
&{ID:1 PointerValue:example-value Inner:{Value:some-value}}
{Value:some-value}
Updated: my meaning of efficiency was "efficient way to use memory"
The assumption that it is more efficient is wrong. The one without pointer is more efficient because there is no need for indirection and the value is in the memory cache along with the other values of Outer. Access will be faster.
Use a pointer when the Inner value is optional. It would have a nil value when the value is absent. Otherwise use the form without pointer. You would also use a pointer if the value of Inner in the JSON string may be null.

Get length of nullable string

I have the following structure:
type NetAuth struct {
Identificator *string `json:"identificator"`
Password *string `json:"password"`
DeviceID *string `json:"deviceId"`
Type int `json:"type"`
}
I am trying to get the length of Identificator with len(event.Identificator) however I get Invalid argument for len
Before calling len I check if it's nil. I am coming from Java/C#/PHP background and it's my first time writing in GO.
There is no simple len(string) concept in Go. You either need the number of bytes in the string representation or the number of characters (so called runes). For ASCII strings both values are the same while for unicode-encoded strings they are usually different.
import "unicode/utf8"
// Firt check that the pointer to your string is not nil
if nil != event.Identificator {
// For number of runes:
utf8.RuneCountInString(*event.Identificator)
// For number of bytes:
len(*event.Identificator)
}
For more information you can check this answer https://stackoverflow.com/a/12668840/1201488.
UPD: event.Identificator is a pointer to a string value in the NetAuth structure rather than a string value. So you need to dereference it first via *event.Identificator.
You are using a pointer, so try this:
println(len(*vlr.Identificator))
For example,
package main
import (
//"fmt"
"encoding/json"
"strings"
"io"
)
type NetAuth struct {
Identificator *string `json:"identificator"`
Password *string `json:"password"`
DeviceID *string `json:"deviceId"`
Type int `json:"type"`
}
func jsondata() io.Reader {
return strings.NewReader(`{"identificator": "0001", "password": "passkey"}`)
}
func main() {
dec := json.NewDecoder(jsondata())
vlr := new(NetAuth)
dec.Decode(vlr)
println(*vlr.Identificator)
println(len(*vlr.Identificator))
}
Playground: https://play.golang.org/p/duf0tEddBsR
Output:
0001
4

Exporting functions with anonymous struct as a parameter [cannot use value (type struct {...}) as type struct {...} in argument to package.Func]

Here is a piece of code play.google.org that runs without any problem:
package main
import (
"fmt"
)
func PrintAnonymous(v struct {
i int
s string
}) {
fmt.Printf("%d: %s\n", v.i, v.s)
}
func PrintAnonymous2(v struct{}) {
fmt.Println("Whatever")
}
func main() {
value := struct {
i int
s string
}{
0, "Hello, world!",
}
PrintAnonymous(value)
PrintAnonymous2(struct{}{})
}
However, if the PrintAnonymous() function exists in another package (let's say, temp), the code will not work:
cannot use value (type struct { i int; s string })
as type struct { i int; s string } in argument to temp.PrintAnonymous
My question are:
Is there a way to call a (public) function with anonymous struct as a parameter (a.k.a. PrintAnonymous() above)?
A function with empty struct as a parameter (a.k.a. PrintAnonymous2() above) can be called even if it exists in another package. Is this a special case?
Well, I know that I can always name the struct to solve the problem, I'm just curious about this, and wonder why it seems that this is not allowed.
The fields of your anonymous struct type are unexported. This means you cannot create values of this struct and specify values for the fields from another package. Spec: Composite literals:
It is an error to specify an element for a non-exported field of a struct belonging to a different package.
If you change the struct definition to export the fields, then it will work because all fields can be assigned to by other packages (see Siu Ching Pong -Asuka Kenji-'s answer).
This is the case with the empty struct (with no fields) too: the empty struct has no fields, thus it has no unexported fields, so you're allowed to pass a value of that.
You can call the function with unmodified struct (with unexported fields) via reflection though. You can obtain the reflect.Type of the PrintAnonymous() function, and you can use Type.In() to get the reflect.Type of its first parameter. That is the anonymous struct we want to pass a value for. And you can construct a value of that type using reflect.New(). This will be a reflect.Value, wrapping a pointer to the zero value of the anonymous struct. Sorry, you can't have a struct value with fields having non-zero values (for reason mentioned above).
This is how it could look like:
v := reflect.ValueOf(somepackage.PrintAnonymous)
paramt := v.Type().In(0)
v.Call([]reflect.Value{reflect.New(paramt).Elem()})
This will print:
0:
0 is zero value for int, and "" empty string for string.
For deeper inside into the type system and structs with unexported fields, see related questions:
Identify non builtin-types using reflect
How to clone a structure with unexported field?
Interestingly (this is a bug, see linked issue below), using reflection, you can use a value of your own anonymous struct type (with matching, unexported fields), and in this case we can use values other than the zero value of the struct fields:
value := struct {
i int
s string
}{
1, "Hello, world!",
}
v.Call([]reflect.Value{reflect.ValueOf(value)})
Above runs (without panic):
1: Hello, world!
The reason why this is allowed is due to a bug in the compiler. See the example code below:
s := struct{ i int }{2}
t := reflect.TypeOf(s)
fmt.Printf("Name: %q, PkgPath: %q\n", t.Name(), t.PkgPath())
fmt.Printf("Name: %q, PkgPath: %q\n", t.Field(0).Name, t.Field(0).PkgPath)
t2 := reflect.TypeOf(subplay.PrintAnonymous).In(0)
fmt.Printf("Name: %q, PkgPath: %q\n", t2.Name(), t2.PkgPath())
fmt.Printf("Name: %q, PkgPath: %q\n", t2.Field(0).Name, t2.Field(0).PkgPath)
Output is:
Name: "", PkgPath: ""
Name: "i", PkgPath: "main"
Name: "", PkgPath: ""
Name: "i", PkgPath: "main"
As you can see the unexported field i in both anonymous struct types (in main package and in somepackage as parameter to PrintAnonymous() function) –falsely– report the same package, and thus their type will be equal:
fmt.Println(t == t2) // Prints true
Note: I consider this a flaw: if this is allowed using reflection, then this should be possible without using reflection too. If without reflection the compile-time error is justified, then using reflection should result in runtime panic. I opened an issue for this, you can follow it here: issue #16616. Fix currently aims Go 1.8.
Oh! I just realized that the field names are in lowercase, and thus not public! Changing the first letter of the field names to uppercase solves the problem:
package main
import (
"temp"
)
func main() {
value := struct {
I int
S string
}{
0, "Hello, world!",
}
temp.PrintAnonymous(value)
temp.PrintAnonymous2(struct{}{})
}
package temp
import (
"fmt"
)
func PrintAnonymous(v struct{I int; S string}) {
fmt.Printf("%d: %s\n", v.I, v.S)
}
func PrintAnonymous2(v struct{}) {
fmt.Println("Whatever")
}

Nameless fields in Go structs?

package main
import "fmt"
type myType struct {
string
}
func main() {
obj := myType{"Hello World"}
fmt.Println(obj)
}
What is the purpose of nameless fields in structs?
Is it possible to access these fields like you can do with named fields?
No disrespect to the chosen answer, but it did not clarify the concept for me.
There are two things going on. First is anonymous fields. Second is the "promoted" field.
For anonymous fields, the field name you can use is the name of the type. The first anonymous field is "promoted", which means any field you access on the struct "passes through" to the promoted anonymous field. This shows both concepts:
package main
import (
"fmt"
"time"
)
type Widget struct {
name string
}
type WrappedWidget struct {
Widget // this is the promoted field
time.Time // this is another anonymous field that has a runtime name of Time
price int64 // normal field
}
func main() {
widget := Widget{"my widget"}
wrappedWidget := WrappedWidget{widget, time.Now(), 1234}
fmt.Printf("Widget named %s, created at %s, has price %d\n",
wrappedWidget.name, // name is passed on to the wrapped Widget since it's
// the promoted field
wrappedWidget.Time, // We access the anonymous time.Time as Time
wrappedWidget.price)
fmt.Printf("Widget named %s, created at %s, has price %d\n",
wrappedWidget.Widget.name, // We can also access the Widget directly
// via Widget
wrappedWidget.Time,
wrappedWidget.price)
}
Output is:
Widget named my widget, created at 2009-11-10 23:00:00 +0000 UTC m=+0.000000001, has price 1234
Widget named my widget, created at 2009-11-10 23:00:00 +0000 UTC m=+0.000000001, has price 1234```
See "Embedding in Go ": you embed an anonymous field in a struct: this is generally used with an embedded struct, not a basic type like string. That type has no "promoted field" to expose.
A field or method f of an anonymous field in a struct x is called promoted if x.f is a legal selector that denotes that field or method f.
Promoted fields act like ordinary fields of a struct except that they cannot be used as field names in composite literals of the struct.
(here string has no field in itself)
See an example of type embedding in "Embeddding when to use pointer".
Is it possible to access these fields like you can do with named fields?
A fmt.Println(obj.string) would return Hello World instead of {Hello World}.

Go Redefined type formating and methods

Here is a basic go program
package main
import (
"fmt"
"time"
)
type myTime time.Time
func main() {
my := myTime(time.Now())
fmt.Println(my)
normal := time.Now()
fmt.Println(normal)
}
And the corresponding output
{63547112172 291468455 0x545980}
2014-09-23 23:36:12.292132305 +0000 UTC
I would like to know why myTime prints diffrently than time.Time. They basically are supposed to be from the same type... Also, if I try to access any method of time.Time, let's say, Day, it's available for "normal" but not for "my".
Thanks!
Your new type does not inherit methods from time.Time. To quote the spec:
The declared type does not inherit any methods bound to the existing type
Since there is no String method, it won't print a meaningful value. You need to implement that yourself.
Your other option is to embed time.Time in your own type. That way you can include the functionality of time.Time but also add your own functionality.
Playground link: http://play.golang.org/p/PY6LIBoP6H
type myTime struct {
time.Time
}
func (t myTime) String() string {
return "<Custom format here>"
}
func main() {
my := myTime{time.Now()}
fmt.Println(my)
normal := time.Now()
fmt.Println(normal)
}
fmt.Println uses the String() method (or rather the fmt.Stringer interface) when formatting a type as a string, if it is available. When you create a new type using an underlying type (in your case time.Time):
type myTime time.Time
You will not inherit the methodset of the underlying type. Therefore, myTime has no String() method, so fmt will use the default format for a struct.

Resources