How to init a global map

2,111 views
Skip to first unread message

Tong Sun

unread,
Jun 23, 2016, 6:12:05 PM6/23/16
to golang-nuts
My mind is not working and I can't find how to fix the following program (https://play.golang.org/p/oXxUndUSye):


package main


import (
 
"fmt"
)


type
set map[string]struct{}


var validSub set


func init
() {
 validSub
.Init([]string{"aa", "bb", "cc"})
 fmt
.Printf("%+v\n", validSub)
}


func
(s set) Init(slice []string) {
 s
= make(map[string]struct{}, len(slice))
 
for _, s1 := range slice {
 s
[s1] = struct{}{}
 
}
}


func
(s set) Has(a string) bool { _, ok := s[a]; return ok }


func main
() {
 fmt
.Println(validSub.Has("aa"))
 fmt
.Println(validSub.Has("dd"))
}



Please help.

Val

unread,
Jun 23, 2016, 6:19:49 PM6/23/16
to golang-nuts
Assigning a value to the receiver will only affect local variable.
Try pointer receiver.

Tong Sun

unread,
Jun 23, 2016, 6:22:20 PM6/23/16
to golang-nuts
I did tried to change to, 

func (s *set) Init(slice []string) {

but that gave loads of errors that I can't fix, hence the question. 


On Thu, Jun 23, 2016 at 6:19 PM, Val <dele...@gmail.com> wrote:
Assigning a value to the receiver will only affect local variable.
Try pointer receiver.

--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/rssS79X7aUs/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Tong Sun

unread,
Jun 23, 2016, 6:24:53 PM6/23/16
to golang-nuts
Is it possible to fix and make the 

validSub.Init([]string{"aa", "bb", "cc"})

works instead? 

Coming from the OO world, this is a form that I feel more comfort with. 

Thx. 

---------- Forwarded message ----------
From: andrey mirtchovski <mirtc...@gmail.com>
Date: Thu, Jun 23, 2016 at 6:16 PM
Subject: Re: [go-nuts] How to init a global map
To: Tong Sun <sunto...@gmail.com>


if you just want to fix it:

https://play.golang.org/p/cL0svI8FU4
> --
> You received this message because you are subscribed to the Google Groups
> "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an

Val

unread,
Jun 23, 2016, 6:28:37 PM6/23/16
to golang-nuts

Tong Sun

unread,
Jun 23, 2016, 6:30:32 PM6/23/16
to Val, golang-nuts
wow, that way. Thanks!

On Thu, Jun 23, 2016 at 6:28 PM, Val <dele...@gmail.com> wrote:
https://play.golang.org/p/DTtGs3FiwZ

andrey mirtchovski

unread,
Jun 23, 2016, 6:40:17 PM6/23/16
to Tong Sun, Val, golang-nuts
line 17 can become:

*s = make(set, len(slice))

Val

unread,
Jun 23, 2016, 6:54:44 PM6/23/16
to golang-nuts
Even in OO style (e.g. java), you would not be able to write
Set s = null;
s.init( list(1,2,3) );

This is (more or less) the same problem with value receiver.
However, map is a reference type, so once the map has been created you really can use value receiver : https://play.golang.org/p/FePU2I-u2-

If your concern is about "allocating a map with make, exactly the size of the input slice", then consider that the "constructor-like" idiom in go is a function NewSet, not a method :
https://play.golang.org/p/6H1ThzyhbM

Val

unread,
Jun 23, 2016, 7:13:02 PM6/23/16
to golang-nuts
Sorry, last link should be: https://play.golang.org/p/_n56yMhlRt

Writing all this on smartphone is possible but tedious and error-prone!

Tong Sun

unread,
Jun 23, 2016, 8:20:01 PM6/23/16
to Val, golang-nuts

On Thu, Jun 23, 2016 at 6:54 PM, Val  wrote:
Even in OO style (e.g. java), you would not be able to write
 Set s = null;
 s.init( list(1,2,3) );

This is (more or less) the same problem with value receiver... the "constructor-like" idiom in go is a function NewSet, not a method :
 https://play.golang.org/p/_n56yMhlRt

* Now* I understand the reason behind such idiom in go. Yep, everything makes sense now.

Thanks a lot for the clear explanation. 
That really helps. 

Hmm... wait, 

map is a reference type

Does that means that, this function

    func (s set) Has(a string) bool { _, ok := s[a]; return ok }

is exactly the same as the following? 

    func (s *set) Has(a string) bool { _, ok := (*s)[a]; return ok }

I.e., even the set is super super big, there is no pass-by-value penalty in the first version? 

Thx

Tamás Gulácsi

unread,
Jun 24, 2016, 12:40:52 AM6/24/16
to golang-nuts
No penalty - a map is already a pointer.

Tong Sun

unread,
Jun 24, 2016, 9:29:25 AM6/24/16
to golang-nuts
(Thanks a lot for all your help Val!)

One last question, which I wasn't able to find myself from https://blog.golang.org/go-maps-in-action

Since a map is a pointer, for any function that take map as a parameter, or function like, 

 func (s set) Something(xxx) 

Does it means the map values can be changed inside the function? 

If yes, what's the proper way to declare it so as to make sure the values cannot be changed inside the function? 

Thanks, and sorry if the question seems too dumb. 


---------- Forwarded message ----------
From: Valentin Deleplace @gmail.com
Date: Fri, Jun 24, 2016 at 2:11 AM
Subject: Re: [go-nuts] How to init a global map
To: Tong Sun @gmail.com

No penalty, passing a map around never copies the values.
But a "pointer to a pointer" receiver is not strictly the same as a pointer receiver.

Val

unread,
Jun 24, 2016, 9:43:05 AM6/24/16
to golang-nuts
These questions are not dumb. On the contrary, "by reference" vs "by values" is a fundamental question in most languages, and the source of many headaches when used incorrectly so it's worth taking some time to ask and get it right.

Yes you may change the values of an existing map, inside any function or method.

Go doesn't provide idiomatic ways to have "immutable-like" or "view-like" builtin containers, except string which are always immutable.  When you have an array, or a slice, or a map, you can always alter its content.
Having said this, if you don't want to caller to modify the data, you may :
- clone the data (make a copy of the map, you have to explicitly loop for that) and give the clone to the caller. This is called "defensive copying".
- or create custom struct type, containing unexported map, with exported read-only accessors e.g.   func (c *MyCustomContainer) Get(key string) Value

Cheers

Tong Sun

unread,
Jun 24, 2016, 9:55:45 AM6/24/16
to Val, golang-nuts
Two thumbs up, Val!

FTA, all your valuable input has been archived and documented at

--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/rssS79X7aUs/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages