How can I pass a dynamic array struct as parameter in golang
For e.g
type Dog {
Name string
}
type Cat {
Name uint
}
I want a function which takes array of either cat or dog as an argument and loop through the array in the function . Below is function of what I wanna achive
func (array of either cats or dogs ){
for _ , item := range (array of either cats or dogs) {
}
}
I am assuming you mean
type Dog struct{
Name string
}
type Cat struct{
Name uint
}
Your function should accept interface{} as an argument, so you are free to send either Dog or Cat or whatever you want as an argument. But after accepting the data you need to apply Type assertion inside the function to extract the specific data type in order to loop over it as you can't loop over the interface.
x := args.(type) // x will contain the name of the data type store inside the interface{}
Or you could use
x := i.(Dog) //if you're absolutely sure that the data type is Dog
x, ok := i.(Cat) //If you're not sure and want to avoid runtime panic
Please read the Go Tour examples to learn more about type assertions.
Edit:
In the comments #mkopriva suggested func F(slice ...interface{}), so you need to convert the slice of Dog or Cat to slice of interface{} for that function signature to work. You will have manually to add/append each element in the Cat or Dog slice to an interface{} slice to convert from slice of Cat or Dog to slice of interface{} slice.
interface{} is one way to go, as mentioned in Answers.
I find the other interfaces also useful:
import (
"fmt"
)
type Pet interface{}
type Dog struct {
Pet
Name string
}
type Cat struct {
Pet
Name uint
}
func listPets(pets []Pet) {
for _, pet := range pets {
fmt.Println(pet)
}
}
func main() {
pets := []Pet{Dog{Name: "Rex"}, Dog{Name: "Boss"}, Cat{Name: 394}}
listPets(pets)
}
https://play.golang.org/p/uSiYmcrSuqJ
Related
Edit: This is not the right way to use interfaces in Go. The purpose of this question is for me to understand how empty interfaces work in Go.
If all types in Go implement interface{} (empty interface), why can't I access the name field in the Cat and Dog structs? How can I get access to the name field of each struct through the function sayHi()?
package main
import (
"fmt"
)
func sayHi(i interface{}) {
fmt.Println(i, "says hello")
// Not understanding this error message
fmt.Println(i.name) // i.name undefined (type interface {} is interface with no methods)
}
type Dog struct{
name string
}
type Cat struct{
name string
}
func main() {
d := Dog{"Sparky"}
c := Cat{"Garfield"}
sayHi(d) // {Sparky} says hello
sayHi(c) // {Garfield} says hello
}
An interface{} is a method set, not a field set. A type implements an interface if it's methods include the methods of that interface. Since empty interface doesn't have any methods, all types implement it.
If you need to access a field, you have to get the original type:
name, ok:=i.(Dog).name
This will recover the name if i is a Dog.
Alternatively, implement a getName() function for both Dog and Cat, and then they will both implement the following interface:
type NamedType interface {
getName() string
}
Then you can rewrite your function as:
func sayHi(i NamedType) {
fmt.Println(i.getName())
}
You can't do that because interface values don't do that.
What interface values do—regardless of the interface type itself; it doesn't matter if the interface type is empty or not—is that they hold two things:
the concrete type of some value (or no type); and
the value of that concrete type (or no value).
So if some variable v or expression e has type I where I is an interface type, then you can, with some syntax, inspect either or both of these two "fields". They're not struct fields so you can't just use v.type, but you can do this:
switch v.(type) {
case int: // the value in v has type int
case *float64: // the value in v has type float64
// etc
}
The .(type) in a switch means let me look at the type field.
Getting the actual value is harder, because Go more or less requires that you check the type first. In your case, you know that i holds either a Dog or a Cat, so you can write:
var name string
switch i.(type) {
case Dog: name = i.(Dog).name
case Cat: name = i.(Cat).name
default: panic("whatever 'i' is, it is not a Dog or Cat")
}
fmt.Println(name)
This is pretty clumsy, and there are lots of ways to make it less clumsy, but that's always the first step: figure out what the type is.
Well, sometimes there's a step before the first step: figure out whether the variable has anything at all in it. You do this with:
if i == nil {
...
}
Note, however, that if i has some typed value in it, and the type can hold nil pointers, the value part of i can be nil and yet i == nil will be false. That's because i does have a type in it.
var i interface{}
var p *int
if i == nil {
fmt.Println("i is initially nil")
}
if p == nil {
fmt.Println("p is nil")
}
i = p
if i != nil {
fmt.Printf("i is now not nil, even though i.(*int) is %v\n", i.(*int))
}
(try this on the Go playground).
This usually isn't the right way to use interface
Most often—there are exceptions—we don't even try to look at the type of some interface. Instead, we define an interface that provides methods—functions we can call—that do something we need done. See Burak Serdar's answer in which the interface type has a getName method. Then, instead of trying to figure out which of some limited set of types someone gave us, we just say:
name := i.getName()
to invoke the getName method on the underlying concrete value. If i holds a Dog, that calls func (Dog) getName() string, which you'll need to define. If i holds a Cat, it calls func (Cat) getName() string. If you decide to add to your collection a type named Bird, you can define func (Bird) getName() string, and so on.
(Usually, the methods would be exported too: GetName, rather than getName.)
Like you say, interface{} is an empty interface. How can you assume that something "empty" has a name field in it (fmt.Println(i.name))? You can't. In fact, go doesn't support fields in interfaces, only methods.
What you can do (and there are, of course, many solutions), is to define an interface (let's call it Pet) which has a method returning the pet's name:
type Pet interface {
getName() string
}
Then you can receive this interface (its object) in the sayHi function and use it to print the pet's name:
func sayHi(i Pet) {
fmt.Println(i.getName())
}
Now, in order to be able to pass Dog or Cat to sayHi(), both of these structs have to implement the interface. So, define the getName() methods for them:
func (d Dog) getName() string {
return d.name
}
func (c Cat) getName() string {
return c.name
}
And that's it.
It can also be implemented using switch type as below-
package main
import (
"fmt"
)
func sayHi(i interface{}) {
fmt.Println(i, "says hello")
switch x := i.(type) {
case Dog:
fmt.Println(x.name)
case Cat:
fmt.Println(x.name)
}
}
type Dog struct {
name string
}
type Cat struct {
name string
}
func main() {
d := Dog{"Sparky"}
c := Cat{"Garfield"}
sayHi(d) // {Sparky} says hello
sayHi(c) // {Garfield} says hello
}
Playground link - https://go.dev/play/p/p4s3_jmmbGJ
I have a slice of struct []student, and I want to modify its content with function.
type student struct {
name string
age int
}
students := []student{
{"Doraemon", 30},
{"King Kong", 25},
}
Thus, I decided to pass it as a pointer. May I know how to pass the slice as a reference to a function?
func addAge (s *[]student) error { //this code has error
//everyone add 2 years old
for i, e := range *s {
s[i].age = s[i].age + 2
}
//make the first student much older
s[0].age = s[0].age + 5
return nil
}
I keep playing with Go Playground, but it gives many complains, such as
cannot range over s (type *[]student)
invalid operation: s[i] (type *[]student does not support indexing)
invalid indirect of s
...
How to precisely pass the reference of a slice of struct to a function? How to range the slice of struct? And how to change the value of the struct (modify the same struct in THE slice)?
I keep getting error while playing with s *[]student, range *s, s []student, s *[]*student ... so hard to get it correct...
sorry for my NEWBIE question, still learning GO... trying hard
Slices are passed by reference, so as long as you are modifying the existing slice content you should not explicitly pass a pointer.
package main
import (
"fmt"
)
type student struct {
name string
age int
}
func main() {
students := []student{
{"Doraemon", 30},
{"King Kong", 25},
}
err := addAge (students)
fmt.Println(students)
if err != nil {
fmt.Println("error")
}
}
func addAge (s []student) error {
for i, _ := range s {
s[i].age = 3
}
return nil
}
Now, for your addAdditinalStudent function you should actually use the append function. Plus, have in mind
..., since the slice header is always updated by a call to
append, you need to save the returned slice after the call. In fact,
the compiler won't let you call append without saving the result.
Slices#append
// add student
students = append(students, student{"Test", 33})
Go Playground
in Go you can pass items by value ([]student) or by reference ([]*student). When you want to operate on the values of a struct{} you should pass it to a function with its reference (the pointer).
So you can do something like this:
type student struct {
name string
age int
}
func addTwoYearsToAll(students []*student){
for _, s := range students {
s.age += 2
}
}
This way you're working with the same exact items you build when appending to the slice. Playground example.
Also take a look at Are Golang function parameter passed as copy-on-write?
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.
There are multiple answers/techniques to the below question:
How to set default values to golang structs?
How to initialize structs in golang
I have a couple of answers but further discussion is required.
One possible idea is to write separate constructor function
//Something is the structure we work with
type Something struct {
Text string
DefaultText string
}
// NewSomething create new instance of Something
func NewSomething(text string) Something {
something := Something{}
something.Text = text
something.DefaultText = "default text"
return something
}
Force a method to get the struct (the constructor way).
From this post:
A good design is to make your type unexported, but provide an exported constructor function like NewMyType() in which you can properly initialize your struct / type. Also return an interface type and not a concrete type, and the interface should contain everything others want to do with your value. And your concrete type must implement that interface of course.
This can be done by simply making the type itself unexported. You can export the function NewSomething and even the fields Text and DefaultText, but just don't export the struct type something.
Another way to customize it for you own module is by using a Config struct to set default values (Option 5 in the link). Not a good way though.
One problem with option 1 in answer from
Victor Zamanian is that if the type isn't exported then users of your package can't declare it as the type for function parameters etc. One way around this would be to export an interface instead of the struct e.g.
package candidate
// Exporting interface instead of struct
type Candidate interface {}
// Struct is not exported
type candidate struct {
Name string
Votes uint32 // Defaults to 0
}
// We are forced to call the constructor to get an instance of candidate
func New(name string) Candidate {
return candidate{name, 0} // enforce the default value here
}
Which lets us declare function parameter types using the exported Candidate interface.
The only disadvantage I can see from this solution is that all our methods need to be declared in the interface definition, but you could argue that that is good practice anyway.
There is a way of doing this with tags, which
allows for multiple defaults.
Assume you have the following struct, with 2 default
tags default0 and default1.
type A struct {
I int `default0:"3" default1:"42"`
S string `default0:"Some String..." default1:"Some Other String..."`
}
Now it's possible to Set the defaults.
func main() {
ptr := &A{}
Set(ptr, "default0")
fmt.Printf("ptr.I=%d ptr.S=%s\n", ptr.I, ptr.S)
// ptr.I=3 ptr.S=Some String...
Set(ptr, "default1")
fmt.Printf("ptr.I=%d ptr.S=%s\n", ptr.I, ptr.S)
// ptr.I=42 ptr.S=Some Other String...
}
Here's the complete program in a playground.
If you're interested in a more complex example, say with
slices and maps, then, take a look at creasty/defaultse
From https://golang.org/doc/effective_go.html#composite_literals:
Sometimes the zero value isn't good enough and an initializing constructor is necessary, as in this example derived from package os.
func NewFile(fd int, name string) *File {
if fd < 0 {
return nil
}
f := new(File)
f.fd = fd
f.name = name
f.dirinfo = nil
f.nepipe = 0
return f
}
What about making something like this:
// Card is the structure we work with
type Card struct {
Html js.Value
DefaultText string `default:"html"` // this only works with strings
}
// Init is the main function that initiate the structure, and return it
func (c Card) Init() Card {
c.Html = Document.Call("createElement", "div")
return c
}
Then call it as:
c := new(Card).Init()
I found this thread very helpful and educational. The other answers already provide good guidance, but I wanted to summarize my takeaways with an easy to reference (i.e. copy-paste) approach:
package main
import (
"fmt"
)
// Define an interface that is exported by your package.
type Foo interface {
GetValue() string // A function that'll return the value initialized with a default.
SetValue(v string) // A function that can update the default value.
}
// Define a struct type that is not exported by your package.
type foo struct {
value string
}
// A factory method to initialize an instance of `foo`,
// the unexported struct, with a default value.
func NewFoo() Foo {
return &foo{
value: "I am the DEFAULT value.",
}
}
// Implementation of the interface's `GetValue`
// for struct `foo`.
func (f *foo) GetValue() string {
return f.value
}
// Implementation of the interface's `SetValue`
// for struct `foo`.
func (f *foo) SetValue(v string) {
f.value = v
}
func main() {
f := NewFoo()
fmt.Printf("value: `%s`\n", f.GetValue())
f.SetValue("I am the UPDATED value.")
fmt.Printf("value: `%s`\n", f.GetValue())
}
One way to do that is:
// declare a type
type A struct {
Filed1 string
Field2 map[string]interface{}
}
So whenever you need a new variable of your custom defined type just call the NewA function also you can parameterise the function to optionally assign the values to the struct fields
func NewA() *A {
return &A{
Filed1: "",
Field2: make(map[string]interface{}),
}
}
for set default values in Go structs we use anonymous struct:
Person := struct {
name string
age int
city string
}{
name: "Peter",
age: 21,
city: "Noida",
}
fmt.Println(Person)
Structs
An easy way to make this program better is to use a struct. A struct is a type which contains named fields. For example we could represent a Circle like this:
type Circle struct {
x float64
y float64
r float64
}
The type keyword introduces a new type. It's followed by the name of the type (Circle), the keyword struct to indicate that we are defining a struct type and a list of fields inside of curly braces. Each field has a name and a type. Like with functions we can collapse fields that have the same type:
type Circle struct {
x, y, r float64
}
Initialization
We can create an instance of our new Circle type in a variety of ways:
var c Circle
Like with other data types, this will create a local Circle variable that is by default set to zero. For a struct zero means each of the fields is set to their corresponding zero value (0 for ints, 0.0 for floats, "" for strings, nil for pointers, …) We can also use the new function:
c := new(Circle)
This allocates memory for all the fields, sets each of them to their zero value and returns a pointer. (*Circle) More often we want to give each of the fields a value. We can do this in two ways. Like this:
c := Circle{x: 0, y: 0, r: 5}
Or we can leave off the field names if we know the order they were defined:
c := Circle{0, 0, 5}
type Config struct {
AWSRegion string `default:"us-west-2"`
}
I have a struct say
type person struct{
name string
phone string
address string
}
and I want to transform it to this (modify phone and address) I only have the object not the struct.
type person2 struct {
name string
phone []struct {
value string
}
address []struct {
value string
}
}
How can I create new struct based on one I have ? I want to transform selected fields only.
I looked into reflection but don't know where to start/how to use it.
Foreword: if you only have the type person and not person2, you have to first write person2. Go is statically typed language, you can't just create person2 at runtime. You may write person2 manually or use go generate by writing the generator code yourself, but it won't be any simpler.
You could also use something like map[string]interface{} to mimic a dynamic struct, but that won't be any friendlier nor faster. Not to mention you'd have to use type assertions as value type is interface{}...
To create a value of person2 from a value of person, you don't need reflection, you can simply manually code it:
func transform(p person) person2 {
return person2{
p.name,
[]struct{ value string }{{p.phone}},
[]struct{ value string }{{p.address}},
}
}
Note that this may look a little weird, and that's because you used a slice of anonymous struct for person2.phone and person2.address, and to initialize an anonymous struct with a composite literal, the anonymous struct definition has to be repeated.
Testing it:
p := person{"Bob", "1234", "New York"}
fmt.Println(p)
p2 := transform(p)
fmt.Println(p2)
Output (try it on the Go Playground):
{Bob 1234 New York}
{Bob [{1234}] [{New York}]}
Note:
Note that your person2 is unnecessarily complex. It could be as simple as this:
type person2 struct {
name string
phones []string
addresses []string
}
And then the transformation is a one-liner:
func transform(p person) person2 {
return person2{p.name, []string{p.phone}, []string{p.address}}
}
Output (try it on the Go Playground):
{Bob 1234 New York}
{Bob [1234] [New York]}