Go variable initilization syntax - go

I notice two styles of initializing a struct type variable in Go code examples but I don't understand when to use each.
Style 1:
package main
import (
"fmt"
)
type Msg struct {
value string
}
func NewMsg(value string) (Msg) {
return Msg{value}
}
func main() {
fmt.Println("Hello, playground")
var helloMsg Msg
helloMsg = NewMsg("oi")
fmt.Println("Hello, ", helloMsg.value)
}
Style 2:
package main
import (
"fmt"
)
type Msg struct {
value string
}
func NewMsg(value string) (Msg) {
return Msg{value}
}
func main() {
fmt.Println("Hello, playground")
var helloMsg Msg
{
helloMsg = NewMsg("oi")
}
fmt.Println("Hello, ", helloMsg.value)
}
The first style is a simples variable initilization but the second is more obscure to me. What the curly braces do? Why should I use the second form?
EDIT:
For more context on the question, it arrised from this sample code of the Go Kit library: https://github.com/go-kit/kit/blob/master/examples/profilesvc/cmd/profilesvc/main.go

What the curly braces do?
They denote a code block. You use code blocks when you want to restrict scope of an identifier (to that block). Here it doesn't make sense, indeed, because you only have one identifier and it's from the outer scope.
Some reading:
Scopes in Go
Blocks in Go

I don't see the difference between these two styles.
They're totally the same.
{} this defines scope codes, and some variables declared inside it can only be used inside that scope.
But if you declare helloMsg outside and do = inside the {} block. 'helloMsg' hasn't been scoped.
So, these two formatted style are totally the same.

Related

Change value of pointered argument inside a function

I'm stuck on something that seems/should be easy in Go.
I wrote a small go playground to explain my problem more easily => https://play.golang.org/p/Sm0SzrvEZS_o
package main
import (
"github.com/sirupsen/logrus"
)
type toto struct {
name string
}
func transform (data ...interface{}) {
logrus.Info("data before ", data)
data[0] = "tutu"
logrus.Info("data after ", data)
}
func main() {
var titi toto
logrus.Info("titi before ", titi) // -> empty
transform(&titi)
logrus.Info("titi after ", titi) // -> should have a name but don't
}
The goal is to pass a struct to a function, modifying in it and continue to use it in the caller function. Sadly, the argument is modified inside the child function but don't move into the caller.
I'm a beginner in this language, maybe I just missed something somewhere... Many thanks in advance for your help
This seems to do it:
package main
type toto struct { name string }
func transform (data ...interface{}) {
t := data[0].(*toto)
t.name = "tutu"
}
func main() {
var titi toto
transform(&titi)
println(titi.name == "tutu")
}
Sounds like you want a pointer.
In your example you use an array of interface{}, is there a particular reason for this? In general you should be explicit with your types in Go, especially since you're dealing with a simple struct.
package main
import (
"log"
)
type toto struct {
Name string
}
// to help with printing
func (t *toto) String() string {
return t.Name
}
// transform takes an array of pointers to the toto struct
func transform(totos ...*toto) {
log.Printf("totos before: %v", totos)
// unsafe array access!
totos[0].Name = "tutu"
log.Printf("totos after: %v", totos)
}
func main() {
// variables in Go are usually defined like this
titi := toto{}
transform(&titi)
}
In Go, the variable that's passed as a parameter in a function is actually a copy of the variable, not the actual variable itself. If you want to modify the variable that's passed, you need to pass it in as a pointer.
Personally, whenever I create a function that accepts a struct, I set the function to accept a pointer to an instance of that struct. This has the benefits of being more memory efficient (since my program doesn't have to create copies of the variable every time the function is called) and it allows me to modify the instance of the struct that I pass.
This is how I would do it:
package main
import (
"github.com/sirupsen/logrus"
)
type toto struct {
name string
}
func transform (t *toto) {
logrus.Info("t before: ", t)
// since t is a pointer to a toto struct,
// I can directly assign "tutu" to the "name" field
// using the "dot" operator
t.name = "tutu"
logrus.Info("t after: ", t)
}
func main() {
// init a pointer to a toto instance
titi := &toto{}
logrus.Info("titi before: ", titi) // -> empty
// this works because transform() accepts a pointer
// to a toto struct and and titi is a pointer to a toto instance
transform(titi)
logrus.Info("titi after (as a pointer): ", titi) // -> not empty
logrus.Info("titi after (as a value): ", *titi) // -> also not empty
}

How do I pass a pointer to a structure in a function?

I wonder how to replace *Type by ? What address has the structure inside?
//mycode.go
package main
import "fmt"
func out(k *Type) {
fmt.Println(k)
}
func main() {
type DataIP struct{ Title, Desc string }
Data := DataIP{
"Hello!",
"Hello GO!",
}
out(&Data)
}
You need to define the type DataIP outside of main() that the type is in the scope of the package and not just inside of the main function:
package main
import "fmt"
type DataIP struct{ Title, Desc string }
func out(k *DataIP) {
fmt.Println(k)
}
func main() {
Data := DataIP{
"Hello!",
"Hello GO!",
}
out(&Data)
}
https://play.golang.org/p/cUS6ttcUy-
I am not sure to understand your question.
If you want out to work only with structs of type DataIP:
simply define DataIP outside of main and use the signature func out(k *DataIP).
if what you want is to be able to pass any type of structure to out:
In golang, this sort of generic methods can be implemented using the interface type. As this answer explains, an interface is a container with two words of data:
one word is used to point to a method table for the value’s underlying type,
and the other word is used to point to the actual data being held by that value.
An interface can hold anything and is often used as a function parameter to be able to process many sort of inputs.
In your case, you can do:
func out(k interface{}) {
fmt.Println(k)
}
This will print &{Hello! Hello GO!}. In case you want the & to disappear (i.e. you always pass it pointers), you can use the reflect package to "dereference" k:
func out(k interface{}) {
fmt.Println(reflect.ValueOf(k).Elem())
}
which yields {Hello! Hello GO!}
Here is a playground example.
if what you want is to print the address of Data:
you can use the %p pattern with fmt.Printf:
fmt.Printf("%p", &Data) // 0x1040a130
Using the out function, you get:
func out(k interface{}) {
fmt.Printf("%p\n", k)
}
See this playground example

Implications of defining a struct inside a function vs outside?

Are there any implications (GC churn, performance, or otherwise) to defining a struct inside a function vs. having it defined outside? For example:
type Outside struct {
Foo string `json:"foo"`
}
func SomeFunc(b []byte) error {
outside := Outside{}
if err := json.NewDecoder(b).Decode(&outside); err != nil {
return err
}
...
}
vs.
func SomeFunc(b []byte) error {
type inside struct {
Foo string `json:"foo"`
}
if err := json.NewDecoder(b).Decode(&inside); err != nil {
return err
}
...
}
Would there be any situation where one is preferred over the other?
To me the main drawback for a type defined in a function is that you cannot define methods on that type.
See this example https://play.golang.org/p/cgH01cRwDv6:
package main
import (
"fmt"
)
func main() {
type MyType struct {
Name string
}
// You cannot define a method on your type
// defined in a function, can you?
func (m MyType) String() string {
return m.Name
}
m := MyType{Name: "Hello, World!"}
fmt.Println(m)
}
The above example will fail with the error prog.go:15:27: expected ';', found 'IDENT' string (and 1 more errors).
There is no performance difference – it's only a difference of scope (i.e., where the type definition can be seen). If you only need the type within a single function, it's fine to define it there.
As others have noted, if you define a type at the package level (i.e., outside of a function) with a name beginning with a capital letter, it will be exported (i.e., visible outside the package). If the name doesn't begin with a capital letter, it will only be visible within the package.
My understanding is the difference is just in accessibility.
A struct defined starting with an upper case letter will be exportable, meaning it can be accessed from other packages.
A struct defined starting with a lower case letter can be accessed from anything within the same package but not externally.
A struct defined in a function inline can only be accessed/initialized by that function.
For me I once defined a struct inside a function for marshalling JSON byte array ([]byte) into the struct instance, and extract a message from the instance.
Obviously it is not required to define the struct. I could have extracted the message by marshalling the JSON byte array into interface{} and then cast recursively to get the required message.
By defining the struct, extraction of the message becomes very easy :)
var errDetail struct {
Message string `json:"message"`
Success bool `json:"success"`
}
json.Unmarshal(*bytes, &errDetail)
if errDetail.Message == "" {
fmt.Println("error message is not present")
return nil
}
return errDetail.Message
As others have mentioned its all about limit the variables scope. If you are going to use a struct inside a function, you could also use an anonymous struct.
package main
import (
"fmt"
)
func main() {
m := struct {
greeting string
name string
}{
greeting: "hello",
name: "world",
}
fmt.Printf("%v %v\n", m.greeting, m.name)
}
If you're only planing to use the struct inside the function you can define the fields of the struct and assign values to them right away.
The scope is different, you can check in Golang spec here:
Most related parts are:
Go is lexically scoped using blocks:
The scope of an identifier denoting a constant, type, variable, or function (but not method) declared at top level (outside any function) is the package block.
The scope of a type identifier declared inside a function begins at the identifier in the TypeSpec and ends at the end of the innermost containing block.
And if you use go tool compile -S -N hello.go to check the generated assembly code, you can spot the names of type defined in package level and names of type defined inside function are different.
Package level
package main
import (
"fmt"
)
type Point struct {
X, Y int
}
func main() {
fmt.Printf("%v\n", Point{X: 1, Y: 2})
}
Then try to compile and find this line: type."".Point SRODATA size=144.
Inside function
package main
import (
"fmt"
)
func main() {
type Point struct {
X, Y int
}
fmt.Printf("%v\n", Point{X: 1, Y: 2})
}
Then try to find this line: type.*"".Point·1 SRODATA size=56
Than means, they just got different names after compiled.
For Konrad Kleine's problem, you can still do it with some workaround like this
https://play.golang.org/p/50yv66LUNRt
package main
import (
"fmt"
)
func main() {
type MyType struct {
Name string
String func() string
}
InitMyType := func(m *MyType) {
m.String = func() string {
return m.Name
}
return
}
m := MyType{Name: "Hello, World!"}
initMyType(&m)
fmt.Println(m.String())
}
I agree the difference is just accessibility.
But this is still very useful, especially what you want is only a temp struct, or when you do unit test, there are many similar struct like args, test case in a package, you won't need bother to name them one by one.

How to have a global variable accessible across all packages

I have a main.go file which has:
// running the router in port 9000
func main() {
router,Global := routers.InitApp()
fmt.println(Global)
router.RunTLS(":9000" , "domain.crt" , "domain.key")
}
In router.InitMap I want to declare a global variable which can be accessed throughout my application anywhere. Is is possible? I tried:
func InitApp() (*gin.Engine,string) {
var Global= "myvalue"
router := gin.New()
return router,Global
}
But I can't access the variable Global even in the same package.
declare a variable at the top level - outside of any functions:
var Global = "myvalue"
func InitApp() (string) {
var Global= "myvalue"
return Global
}
Since the name of the variable starts with an uppercase letter, the variable will be available both in the current package through its name - and in any other package when you import the package defining the variable and qualify it with the package name as in: return packagename.Global.
Here's another illustration (also in the Go playground: https://play.golang.org/p/h2iVjM6Fpk):
package main
import (
"fmt"
)
var greeting = "Hello, world!"
func main() {
fmt.Println(greeting)
}
See also Go Tour: "Variables" https://tour.golang.org/basics/8 and "Exported names" https://tour.golang.org/basics/3.
It is better to use the init function for initialisation of global variables. It also will be processed only once even in multiply includes of this package. https://play.golang.org/p/0PJuXvWRoSr
package main
import (
"fmt"
)
var Global string
func init() {
Global = InitApp()
}
func main() {
fmt.Println(Global)
}
func InitApp() (string) {
return "myvalue"
}
My solution:
define the global variable in other package with Set and Get, similar with class set in python
the good part is that you can set global variables in any package, the bad part is that you can mess up the global variables if you use Set not carefully
https://play.golang.org/p/egApePP7kPq
first define global variable
-- globalvar/globalvar.go --
package globalvar
import "fmt"
var Glbv int
func Set(b int) {
Glbv = b
}
func Get() int {
return Glbv
}
func Pr() {
fmt.Printf("inside globarvar = %v \n", Glbv)
} ```
then you can change the global variable in another package
-- otherpackage/otherpackage.go --
package otherpackage
import (
"fmt"
"play.ground/globalvar"
)
func Bar() {
globalvar.Set(3)
}
func Prtf() {
var cc = globalvar.Get()
fmt.Printf("inside otherpackage globalvar=%v \n", cc)
}
main function
package main
import (
"play.ground/globalvar"
"play.ground/otherpackage"
)
func main() {
globalvar.Pr()
otherpackage.Prtf()
globalvar.Set(2)
globalvar.Pr()
otherpackage.Prtf()
otherpackage.Bar()
globalvar.Pr()
otherpackage.Prtf()
}
here is the result
inside globarvar = 0
inside otherpackage globalvar=0
inside globarvar = 2
inside otherpackage globalvar=2
inside globarvar = 3
inside otherpackage globalvar=3
You can also do it like writing a function to initialise the global variable as:
package main
import (
"fmt"
)
func initialise() string {
CommonVariable = "global_variable"
return CommonVariable
}
var CommonVariable string
func main() {
initialise()
fmt.Println(CommonVariable)
}
If you want to take input from user and then initialise it to global variable, just change the line CommonVariable="myvalue" in initialise() function with "Scanf" statement like this:
func initialise() string {
fmt.Scanln(&CommonVariable)
return CommonVariable
}

Initialize a variable over a function by reference in golang

If I have a function which takes a reference as an argument and I want to use that function to initialize a variable I need to do this inside the init() function. That solution works, but it smells not really correct to me.
Is there another way to initialize a variable for a package in go like to use the init() function?
I think that there must be a better way. I thought already about a wrapping function, but that makes the logik not better.
I prepared a short and simple example
package main
import (
"fmt"
)
var a string
//A use of a function is not allowed
//foo(&a)
//Need to call init
func init() {
foo(&a)
}
func main() {
fmt.Println(a)
}
func foo(b *string) {
*b = "abc"
}
https://play.golang.org/p/GdBiDFB1KAe
That's fine, or you can just make a pointer and assign it like this:
var a = make("abc")
func main() {
fmt.Println(*a)
}
func make(s string) *string {
return &s
}
playground

Resources