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}.
Related
I have a structure that gets rendered via template. e.g.:
type Foo struct {
Created time.Time
...
}
I pass this value to a template, and I'd like to this rendered see:
Created at 2022-11-22 9:50 (0d1h12m34s ago)
Displaying the timestamp (and formatting it) is easy enough, but I can't find a way to calculate the interval.
Created at {{.Created}} ({{???}} ago)
In go, this would be accomplished by time.Since(foo.Created) which returns a Duration, and then I can convert duration to string in various ways.
But doing the calculation in the template itself does not seem possible:
function "time" not defined
Or is it?
Can't find any information that explicitly tells me that time (or other arbitrary functions) are never ever allowed in templates. So I don't know if I'm just calling it wrong.
(I know I could create a new FooTemplateValue from a Foo add that field, so the template can render the duration as-is. I was just trying to avoid it if I can and use the actual object as-is).
You can register a custom template function using template.FuncMap, then you can invoke that function inside the template just like you would invoke a builtin function.
template.New("").Funcs(template.FuncMap{
"dur_until_now": func(t time.Time) time.Duration {
return time.Now().Sub(t)
},
}).Parse(`{{ dur_until_now .Created }}`)
https://go.dev/play/p/wM2f1oDFtDr
Or you can declare a custom time type and have that type implement a method that produces the desired value, then you can invoke that method inside the template directly on the field.
type MyTime struct{ time.Time }
func (t MyTime) DurUntilNow() time.Duration {
return time.Now().Sub(t.Time)
}
// ...
.Parse(`{{ .Created.DurUntilNow }}`)
https://go.dev/play/p/3faW4nTzK3-
Looks like you need to initialize the Created field with time.Now()
package main
import (
"fmt"
"time"
)
type Foo struct {
Created time.Time
// ...
}
func main() {
x := Foo{Created: time.Now()}
fmt.Println(time.Since(x.Created))
}
This question already has answers here:
Embedding instead of inheritance in Go
(7 answers)
Closed last year.
Below is a simple program. But what I don't understand is that how is the Get operation working? I have not defined any Get Method, but form.Get is working. How?
Sincerely,
Sudarsan.D
package main
import (
"fmt"
"net/url"
)
type errors map[string]string;
type Form struct {
url.Values;
Errors errors;
}
func New (data url.Values) (*Form) {
return &Form {
data,
errors(map[string]string{}),
};
}
func main () {
k1 := url.Values{};
k1.Set("arvind","superstar");
k1.Set("title","Arvind");
form := New(k1);
fmt.Println("The title is", form.Get("arvind"));
}
Because in the Form struct you did not provide a name explicitly for the url.Values field, that field is said to be embedded. An embedded field's name is automatically set to the type's unqualified name, i.e. in this case the url.Values field's name becomes Values. Also, an embedded field type's methods (if it has any) and fields (if it is a struct with any) are said to be promoted to the embedding struct. A promoted method or field can be accessed directly through the embedding struct, without having to specify the embedded field's name. i.e. instead of form.Values.Get("arvind") you can do form.Get("arving").
Keep in mind that the two expressions form.Values.Get("arvind") and form.Get("arving") are semantically equivalent. In both cases you are calling the method Get on the form.Values field even though in the second expression the field's name is omitted.
From the language spec on Struct types:
A struct is a sequence of named elements, called fields, each of which
has a name and a type. Field names may be specified explicitly
(IdentifierList) or implicitly (EmbeddedField).
...
A field declared with a type but no explicit field name is called an
embedded field. An embedded field must be specified as a type name T
or as a pointer to a non-interface type name *T, and T itself may not
be a pointer type. The unqualified type name acts as the field name.
...
A field or method f of an embedded field in a struct x is called
promoted if x.f is a legal selector that denotes that field or method
f.
...
Given a struct type S and a defined type T, promoted methods are
included in the method set of the struct as follows:
If S contains an embedded field T, the method sets of S and *S both
include promoted methods with receiver T. The method set of *S also
includes promoted methods with receiver *T.
If S contains an embedded
field *T, the method sets of S and *S both include promoted methods
with receiver T or *T.
I learnt that it is not allowed to embed slices or maps into Go structs. But I found two workarounds to this:
Declare the slice or map outside the struct and embed it into the struct
var mySlice []int
type myStruct struct {
mySlice
}
I don't really understand this second workaround, but I found it's called Composition and it's done by just omitting the var keyword when declaring the slice or map within the struct
type myStruct struct {
mySlice []int
}
My first question is, can anyone explain why we can't directly embed slices and maps into a struct?
Second question: using the second workaround, is there any negative performance effect to that?
Third question: why do the first and second workaround work?
Spec: Struct types:
A field declared with a type but no explicit field name is called an embedded field. An embedded field must be specified as a type name T or as a pointer to a non-interface type name *T, and T itself may not be a pointer type. The unqualified type name acts as the field name.
You can't embed a type like map[int]string, that's an anonymous type. Spec requires a type name. Even if you could embed that, it contains brackets which would make it disqualify from being an identifier, and again, spec says the unqualified type name acts as the field name.
Simply create a new type for it which you can then embed:
type mymap map[int]string
type s struct {
mymap
}
When you embed a type in a struct, you omit the field name. In your second attempt:
type myStruct struct {
mySlice []int
}
You did not omit the field name (it's mySlice), so this is not embedding, it's a regular, named field.
I am looking at the docs for the chi package. I see something like:
https://github.com/pressly/chi/blob/master/_examples/rest/main.go#L154
data := struct {
*Article
OmitID interface{} `json:"id,omitempty"` // prevents 'id' from being overridden
}{Article: article}
How do I interpret this? 2 parts I don't fully understand
How does the OmitID part prevent id from being set?
What does the {Article: article} part do?
The first {} in the struct definition is for define the field or attribute of that struct.
data := struct {
*Article
OmitID interface{} `json:"id,omitempty"` // prevents 'id' from being overridden
}
So the data is a struct that has fields *Article and OmitID with their respected type.
What does the {Article: article} part do?
the second {} is for defining the value of that field.
{Article: article}
this part is defining the value of Article field.
How does the OmitID part prevent id from being set?
In go you can define any number of field in the struct.
And you can call define it by calling the field and the value with the respected type. for example if I have this struct :
type DriverData struct {
Name string `json:"name"`
Status bool `json:"status"`
Location GeoJson `json:"location"`
}
I can call it like this :
example := DriverData{Name : "SampleName"}
the rest of the field will have zero values based on their respective data types.
You can read about golang Zero Values here
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")
}