Implicit type with struct of slices - go

If I have a file like this:
package main
import "fmt"
type Language struct {
Example []string
Link []string
}
func main() {
o := Language{
{".go", "go.ps1"},
{"golang.org", "go.dev"},
}
fmt.Println(o)
}
I get this result:
missing type in composite literal
I found I can resolve like this:
[]string{".go", "go.ps1"},
[]string{"golang.org", "go.dev"},
but is that strictly required? I would think Go would know the type of each
property based on the struct definition.

The problem here is not that the compiler doesn't know the type, it is that the syntax for a composite literal requires the type:
https://golang.org/ref/spec#Composite_literals
A string array literal is []string{"a","b",","c"}, not {"a","b","c"}.

You need field in struct definition, like this
o := Language{
Example: []string{".go", "go.ps1"},
Link: []string{"golang.org", "go.dev"},
}
fmt.Println(o)

Related

Getting "implicit assignment of unexported field"

package main
main.go
import (
"fmt"
"practice/pkg"
)
func main() {
mk := pkg.MustKey{map[string]string{"Hello": "bar"}}
fmt.Printf("%v\n", mk)
}
pkg package
hello.go
package pkg
type MustKey struct {
m map[string]string
}
While executing the following, I am getting error as mentioned in the subject line. Any help will be appreciated.
There is a very important rule in Go - how to Export/unexport any functions/methods/fields.
Export - when the name starts with a Captial letter (say it Public)
unexport - when the name starts with a small letter (say it Private)
So in your case, the struct type name MustKey is exportable (starts with a capital M) and can be accessed outside your defined package pkg. But the map variable m inside the struct does start with a small m, so it cannot be accessed outside the package and private to that package only.
So, you have 2 solutions:
Either use M instead of m, like:
type MustKey struct {
M map[string]string
}
Or, if you still want the map variable private - use Exported methods with helping of interface
type MustKey struct {
m map[string]string
}
func (mk *MustKey) GetValue(key string) (string, error) {
value, ok := m[key]
if !ok {
return "", fmt.Errorf("Key is not available: %s", key)
}
return value, nil
}
func (mk *MustKey) SetValue(key, value string) {
m[key] = value
}
And you can use these Get and Set methods to put your own logic.
Read this for good understanding.
In this code:
type MustKey struct {
m map[string]string
}
the map variable is in lower case so it is un-exported (and only private to that package). In Golang to export any field from one pkg to another it should me in Upper case.
Two solutions:
1) Declare Map fields in Upper case, eg:
type MustKey struct {
// m map[string]string
// Upper case fields can be export to other packages
M map[string]string
}
2) Wrap your structure in one function and export the function name.
MustKey.m is an unexported field. You are attempting to initialize that field without referring to it by name with pkg.MustKey{map[string]string{"Hello": "bar"}}.
You either have to export the field by renaming it to M, or you have to define a constructor function that will set it in the package:
func NewMustKey(m map[string]string) MustKey {
return MustKey{m:m}
}
The field m in the MustKey struct is lower case. Therefore it is an unexported field and cannot be used by a program that imports the pkg package. Unexported fields have to be operated on by methods or functions that are internal to the pkg package. Or change it to an M and then use that externally.
You are implicitly using m when you do the initialization in main.

Type conversion between two struct pointers

I have a struct that consists of a custom time.Time defined for the sake of it having a custom MarshalJSON() interface, following this answer's suggestion:
type MyTime time.Time
func (s myTime) MarshalJSON() ([]byte, error) {
t := time.Time(s)
return []byte(t.Format(`"20060102T150405Z"`)), nil
}
I define a MyStruct type with ThisDate and ThatDate fields of type *MyTime:
type MyStruct struct {
ThisDate *MyTime `json:"thisdate,omitempty"`
ThatDate *MyTime `json:"thatdate,omitempty"`
}
As far as I understand, I need to use *MyTime and not MyTime so the omitempty tag will have an effect when I'll MarshalJSON a variable of this type, following this answer's suggestion.
I use a library that has a function that returns me a struct with some fields of type *time.Time:
someVar := Lib.GetVar()
I tried to define a variable of type MyStruct like this:
myVar := &MyStruct{
ThisDate: someVar.ThisDate
ThatDate: someVar.ThatDate
}
Naturally, it gives me a compilation error:
cannot use someVar.ThisDate (variable of type *time.Time) as *MyTime value in struct literal ...
I tried typecasting someVar.ThisDate with */& and without these without luck. I thought the following would work:
myVar := &MyStruct{
ThisDate: *MyTime(*someVar.ThisDate)
ThatDate: *MyTime(*someVar.ThatDate)
}
But it gives me a different compilation error:
invalid operation: cannot indirect MyTime(*someVar.ThisDate) (value of type MyTime) ...
It seems I probably lack basic understanding of pointers and dereferences in Go. Never the less, I would like to avoid finding a specific solution for my issue which comes down to the combination of the need to make omitempty have an effect and a custom MarshalJSON.
The problem is the ambiguous syntax of *T(v) or whatever else you tried there. The Golang's spec gives useful examples for type conversions as this, quoting:
*Point(p) // same as *(Point(p))
(*Point)(p) // p is converted to *Point
Therefor, since *Point is needed, *T(v) should be used.

In golang, struct with a slice variable of any type is possible?

Simple golang app gives below error
.\test.go:13: cannot use ds (type Data_A) as type []interface {} in field value
for below code
package main
type Data_A struct {
a string
}
type DTResponse struct {
Data []interface{} `json:"data"`
}
func main() {
ds := Data_A{"1"}
dtResp := &DTResponse{ Data:ds}
print(dtResp)
}
I would like to have a struct with slice variable of any type. Using struct{} gives the same error.
In Java I could use Object as it is the parent object of any object. But I could not find such one in golang.
Any help would be appreciated.
Yes, as a slice of interface{} which can hold any arbitrary value.
var s = []interface{}{1, 2, "three", SomeFunction}
fmt.Printf("Hello, %#v \n", s)
Output:
Hello, []interface {}{1, 2, "three", (func())(0xd4b60)}
https://play.golang.org/p/MQMc689StO
But I do not recommend simulate dynamic-typed languages (like Python, JavaScript, PHP, etc) this way. Better to use all static-typed benefits from Go, and leave this feature as a last resort, or as a container for user input. Just to receive it and convert to strict types.
Typing
Go is a strongly explicitly typed language thus you can't substitute an object of one type with another (it is already compiled in this way). Also when you do type Data_A struct {... you define new type named Data_A. []interface{} and Data_A are completely different types and these types (like any other) are not interchangeable. Note, even interface{} is not interchangeable with anything. You can pass any type in a function like this func f(a interface{}){... but inside the function you will have exactly interface{} type and you should assert it to use properly.
Fix#1
package main
type Data_A struct {
a string
}
type DTResponse struct {
Data Data_A `json:"data"`
}
func main() {
ds := Data_A{"1"}
dtResp := &DTResponse{ Data:ds}
print(dtResp)
}
Fix#2
package main
type DTResponse struct {
Data []interface{} `json:"data"`
}
func main() {
ds := []interface{}{"1"}
dtResp := &DTResponse{ Data:ds}
print(dtResp)
}
Possibly the cause of confusion: struct is not slice or array.

Golang embedded struct type

I have these types:
type Value interface{}
type NamedValue struct {
Name string
Value Value
}
type ErrorValue struct {
NamedValue
Error error
}
I can use v := NamedValue{Name: "fine", Value: 33}, but I am not able to use e := ErrorValue{Name: "alpha", Value: 123, Error: err}
Seems that embedding syntax was ok, but using it doesn't work?
Embedded types are (unnamed) fields, referred to by the unqualified type name.
Spec: Struct types:
A field declared with a type but no explicit field name is an anonymous field, also called an embedded field or an embedding of the type in the struct. An embedded type 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.
So try:
e := ErrorValue{NamedValue: NamedValue{Name: "fine", Value: 33}, Error: err}
Also works if you omit the field names in the composite literal:
e := ErrorValue{NamedValue{"fine", 33}, err}
Try the examples on the Go Playground.
For deeply nested structs, the accepted answer's syntax is a little verbose. For example, this :
package main
import (
"fmt"
)
type Alternative struct {
Question
AlternativeName string
}
type Question struct {
Questionnaire
QuestionName string
}
type Questionnaire struct {
QuestionnaireName string
}
func main() {
a := Alternative{
Question: Question{
Questionnaire: Questionnaire{
QuestionnaireName: "q",
},
},
}
fmt.Printf("%v", a)
}
(Go playground)
Could be rewritten like this:
a := Alternative{}
a.QuestionnaireName = "q"
In addition to the wonderful answer by icza.
you can simply do this:
v := NamedValue{Name: "fine", Value: 33}
e := ErrorValue{NamedValue:v, Error: err}
and it works just fine. checkout the example Here

Construct struct literal with embedded structs

How do I construct a struct literal with embedded struct?
Go:
package main
import "fmt"
type Ping struct {
Content struct {
name string
}
}
func main() {
p := Ping{Content{"hello"}}
fmt.Println(p)
}
http://play.golang.org/p/UH4YO6CAFv
This works if I had written the structs this way:
Go:
type Ping struct {
Content
}
type Content struct {
name string
}
http://play.golang.org/p/ERGsO4CMEN
How do I do it with the embedded struct version in the first code version?
You can't, and you really shouldn't either, but if you insist anyway you can use something like:
p := Ping{struct{ name string }{"don't do it"}}
or
p := Ping{}
p.Content.name = "hello"
playground
This doesn't seem to be supported, looking at the spec for Struct type
A field declared with a type but no explicit field name is an anonymous field, also called an embedded field or an embedding of the type in the struct.
An embedded type 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.
That means T must be defined somewhere else.

Resources