Deferencing type maps - dictionary

I am trying to dereference a channel and use the payload in the channel to check if there is an entry in the map or not.
If the map is of not type it works but if the map has a type I always get the error that type <map> is not an expression.
type writechan chan UserProfile
type usersmap map[string]UserProfile
var myuserprofile UserProfile
myuserprofile = <-myuserchannel
var username = myuserprofile.name
if _, ok := usersmap[username]; ok {
fmt.Println("Already registered ")
} else {
usersmap[username] = myuserprofile
}
The error message says type usersmap is not an expression" in the if line . If I don't use the type usermap but a normal map say map[string]string it works fine.

type usersmap map[string]UserProfile
This is a type declaration, it does not create a variable named usersmap. After this type declaration you may use the usersmap (type) identifier to create a variable like this:
var umap usersmap
And to initialize it:
umap = make(usersmap)
Or in one line:
var umap = make(usersmap)
Or using a short variable declaration with initialization:
umap := usersmap{}
Also to create a variable of map type you don't necessarily have to create a new type, you may simply write:
var umap = make(map[string]UserProfile)

Related

Why does Go's package flag use pointers?

Consider the following code from gopl.io/ch2/echo4
package main
import (
"flag"
"fmt"
"strings"
)
var n = flag.Bool("n", false, "omit trailing newline")
var sep = flag.String("s", " ", "separator")
func main() {
flag.Parse()
fmt.Print(strings.Join(flag.Args(), *sep))
if !*n {
fmt.Println()
}
}
I'm interested why the variables n and sep are pointers to the flag variables, rather than normal variable type.
It is because they need to be assigned value after they are created. The order of actions is:
Create variable var n = flag.Bool("n", false, "omit trailing newline") The value is false now.
Assign value with flag.Parse(). Variable is now assigned value passed as command line argument.
If you check the code here, you'll see that there's an exported variable called CommandLine, which is a pointer to a FlagSet. This is where the magic happens. When you import that library, it's instantiated. When you invoke the exported functions, for example, flag.Bool(), that function, in turn, calls the method Bool(), which has a pointer receiver to...FlagSet. It will create a new bool to store your flag's value, invoke BoolVar() to store a pointer to the newly created bool variable within the FlagSet data structure (you'll need to trace BoolVar to see how this is accomplished), and returns the very same pointer to you so you can later get the current value (which could be the default value or an entirely new value as a result of the call toParse())
// CommandLine is the default set of command-line flags, parsed from os.Args.
// The top-level functions such as BoolVar, Arg, and so on are wrappers for the
// methods of CommandLine.
var CommandLine = NewFlagSet(os.Args[0], ExitOnError)
// NewFlagSet returns a new, empty flag set with the specified name and
// error handling property. If the name is not empty, it will be printed
// in the default usage message and in error messages.
func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet {
f := &FlagSet{
name: name,
errorHandling: errorHandling,
}
f.Usage = f.defaultUsage
return f
}
// A FlagSet represents a set of defined flags. The zero value of a FlagSet
// has no name and has ContinueOnError error handling.
//
// Flag names must be unique within a FlagSet. An attempt to define a flag whose
// name is already in use will cause a panic.
type FlagSet struct {
// Usage is the function called when an error occurs while parsing flags.
// The field is a function (not a method) that may be changed to point to
// a custom error handler. What happens after Usage is called depends
// on the ErrorHandling setting; for the command line, this defaults
// to ExitOnError, which exits the program after calling Usage.
Usage func()
name string
parsed bool
actual map[string]*Flag
formal map[string]*Flag
args []string // arguments after flags
errorHandling ErrorHandling
output io.Writer // nil means stderr; use Output() accessor
}
// Bool defines a bool flag with specified name, default value, and usage string.
// The return value is the address of a bool variable that stores the value of the flag.
func (f *FlagSet) Bool(name string, value bool, usage string) *bool {
p := new(bool)
f.BoolVar(p, name, value, usage)
return p
}
// Bool defines a bool flag with specified name, default value, and usage string.
// The return value is the address of a bool variable that stores the value of the flag.
func Bool(name string, value bool, usage string) *bool {
return CommandLine.Bool(name, value, usage)
}
Going back to your question:
why the variables n and sep are pointers to the flag variables, rather than normal variable type.
It's because Parse() can manipulate the original variables and your new variables n and sep would have only captured a copy of the original values. By using the pointer, you and the FlagSet are looking at exact the same variables.

Cannot take the address of map element

I want to find out why
x:= odsMap[segRef]
x.GetValue("#OriginDestinationKey")
works, but this does not:
odsMap[segRef].GetValue("#OriginDestinationKey")
?
The last snippet prints the following errors:
cannot call pointer method on odsMap[segRef]go
cannot take the address of odsMap[segRef]
These errors happen during compilation time (not runtime). So, my main question is why I need an intermediate variable x to access the function?
Regarding the type of the variables odsMap is a map[string] XMLElement and segRef is a string.
Thanks.
Map index expressions are not addressable, because the internals of a map may change when a new entry is added to it, so the spec intentionally does not allow taking its address (this gives greater freedom for map implementations).
This means if you store non-pointers in the map, and you want to call a method of a stored value that has a pointer receiver, that would require to take the address of the non-pointer value (to be used as the receiver), but since map index expressions are not addressable, that results in a compile-time error.
A workaround is to store pointer values in the map, so there is no need to take the address of an index expression, because it's already a pointer. An example of this can be seen in this answer: Why should constructor of Go return address? If we have this type:
type My int
func (m *My) Str() string { return strconv.Itoa(int(*m)) }
This gives the compile-time error in question:
m := map[int]My{0: My(12)}
m[0].Str() // Error!
But this works:
m := map[int]*My{}
my := My(12)
m[0] = &my // Store a pointer in the map
m[0].Str() // You can call it, no need to take the address of m[0]
// as it is already a pointer
Another option is to assign it to a local variable whose address can be taken, and call the pointer method on that. Care must be taken though, as if the method has pointer receiver, it might modify pointed object or its components (e.g. fields of a struct), which would not be reflected in the value stored in the map. If you go down this path, you might have to reassign the value to the key in the map to have the updated value.
All-in-all, if you have a value whose type has methods with pointer receiver, you're better off using it (store, pass) as a pointer and not as a non-pointer value.
See related questions:
Pointer methods on non pointer types
How can I store reference to the result of an operation in Go?
#icza's answer is the correct one.
Here is an example to illustrate how "value receiver" vs "pointer receiver" interact with "pointer map" vs "values map" :
https://play.golang.org/p/JVp6DirgPkU
package main
import (
"fmt"
)
// a simple type, with two methods : one with a value receiver, one with a pointer receiver
type Item struct {
name string
}
func (i Item) GetNameByValue() string {
return i.name
}
func (i *Item) GetNameByRef() string {
return i.name
}
func main() {
{
// in this map, we store *pointers* to Item values
mapByRef := make(map[int]*Item)
mapByRef[0] = &Item{"I am stored as a pointer"}
// GetNameByRef will work on a *Item : "mapByRef[0]" is already a pointer
fmt.Println("GetByRef :", mapByRef[0].GetNameByRef())
// GetNameByValue will work on a *Item : go automatically turns this into '(*mapByRef[0]).GetNameByValue()', and this is valid
fmt.Println("GetByValue :", mapByRef[0].GetNameByValue())
}
{
// in this map, we store Item values (no pointers)
mapByValue := make(map[int]Item)
mapByValue[0] = Item{"I am stored as a value"}
// GetNameByValue will work on a Item : "mapByValue[0]" has the right type
fmt.Println("GetByValue :", mapByValue[0].GetNameByValue())
// GetNameByRef will not work : go tries to turn this into : (&mapByValue[0]).GetNameByRef(),
// and go refuses to let you take the address of a value inside a map
// fmt.Println("GetByRef :", mapByValue[0].GetNameByRef())
// compiler error :
// ./prog.go:47:46: cannot call pointer method on mapByValue[0]
// ./prog.go:47:46: cannot take the address of mapByValue[0]
// you will need some way to copy the value before taking its address :
item := mapByValue[0]
fmt.Println("item.GetByRef :", item.GetNameByRef())
// same as :
fmt.Println("(&item).GetByRef :", (&item).GetNameByRef())
}
}
// Output :
//
// GetByRef : I am stored as a pointer
// GetByValue : I am stored as a pointer
// GetByValue : I am stored as a value
// item.GetByRef : I am stored as a value
// (&item).GetByRef : I am stored as a value

Convert named-type map[string]string to plain one in Golang

I have a map of type set, which is actually a map[string]string. However, passing it to a function which accepts a map[string]string fails, because Go does not recognize set as one.
However, I fail to convince the compiler it is one. Is there any way to resolve this, without looping and copying?
package main
import (
"fmt"
)
type name string
type field string
type set map[name]field // map[string]string after all
type plain map[string]string // also map[string]string
func main() {
var typed = set{"hi": "ho"} // map[string]string?
back := plain(typed) // cannot convert typed (type set) to type plain
back := typed.(plain) // invalid type assertion: typed.(plain) (non-interface type set on left)
echo(back)
}
func echo(in map[string]string) {
fmt.Println(in)
}
You could do this using the unsafe package.
Note: I don't think this would necessarily be a good idea, and probably the right way would be to just iterate and copy, but since it does answer the question asked...
var typed = set{"hi": "ho"} // map[string]string?
p := unsafe.Pointer(&typed)
var back plain
back = *(*plain)(p)
Playground: https://play.golang.org/p/yienSuJSnQU

Assign value to optional dictionary in Swift

I'm finding some surprising behavior with optional dictionaries in Swift.
var foo:Dictionary<String, String>?
if (foo == nil) {
foo = ["bar": "baz"]
}
else {
// Following line errors with "'Dictionary<String, String>?' does
// not have a member named 'subscript'"
foo["qux"] = "quux"
}
I've played with this a lot, trying to figure out what I might be missing, but nothing seems to make this code work as expected short of making the dictionary not optional. What am I missing?
The closest I can get is the following, but of course it's ridiculous.
var foo:Dictionary<String, String>?
if (foo == nil) {
foo = ["bar": "baz"]
}
else if var foofoo = foo {
foofoo["qux"] = "quux"
foo = foofoo
}
The lightbulb moment is when you realize that an Optional dictionary is not a Dictionary. An Optional anything is not that thing! It is an Optional!! And that's all it is. Optional is itself a type. An Optional is just an enum, wrapping the possible cases nil and some value. The wrapped value is a completely different object, stored inside.
So an Optional anything does not act like the type of that thing. It is not that thing! It is just an Optional. The only way to get at the thing is to unwrap it.
The same is true of an implicitly unwrapped Optional; the difference is just that the implicitly unwrapped Optional is willing to produce (expose) the wrapped value "automatically". But it is still, in fact, wrapped. And, as Bryan Chen has observed, it is wrapped immutably; the Optional is just holding it for you - it is not giving you a place to play with it.
you can use this code
if var foofoo = foo {
foofoo["qux"] = "quux"
foo = foofoo
} else {
foo = ["bar": "baz"]
}
with this code
var foo:Dictionary<String, String>? = Dictionary()
foo[""]=""
error: 'Dictionary<String, String>?' does not have a member named 'subscript'
foo[""]=""
^
the error message makes sense to me that Dictionary<String, String>? does not implement subscript method, so you need to unwrap it before able to use subscript.
one way to call method on optional is use ! i.e. foo![""], but...
var foo:Dictionary<String, String>? = Dictionary()
foo![""]=""
error: could not find member 'subscript'
foo![""]=""
~~~~~~~~^~~
whereas
var foo:Dictionary<String, String>? = Dictionary()
foo![""]
works
it is interesting these code failed to compile
var foo:Dictionary<String, String>! = Dictionary() // Implicitly unwrapped optional
foo[""]=""
error: could not find an overload for 'subscript' that accepts the supplied arguments
foo[""]=""
~~~~~~~^~~
var foo:Dictionary<String, String>! = Dictionary() // Implicitly unwrapped optional
foo.updateValue("", forKey: "")
immutable value of type 'Dictionary<String, String>' only has mutating members named 'updateValue'
foo.updateValue("", forKey: "")
^ ~~~~~~~~~~~
the last error message is most interesting, it is saying the Dictionary is immutable, so updateValue(forKey:) (mutating method) can't be called on it
so what happened is probably that the Optional<> store the Dictionary as immutable object (with let). So even Optional<> it is mutable, you can't modify the underlying Dictionary object directly (without reassign the Optional object)
and this code works
class MyDict
{
var dict:Dictionary<String, String> = [:]
subscript(s: String) -> String? {
get {
return dict[s]
}
set {
dict[s] = newValue
}
}
}
var foo:MyDict? = MyDict()
foo!["a"] = "b" // this is how to call subscript of optional object
and this lead me to another question, why Array and Dictionary are value type (struct)? opposite to NSArray and NSDictionary which are reference type (class)
This is because your Dictionary is optional. If it's nil, you won't add an entry to it.
You can do this way:
var dict: [String : String]?
if let dict = dict {
dict["key"] = "value" // add a value to an existing dictionary
} else {
dict = ["key" : "value"] // create a dictionary with this value in it
}
Or, if you are given an optional dictionary, for example HTTPHeaders - which in AlamoFire is a [String : String] dictionary - and you want to either add a value if it's non-nil, or create it with this value if it's nil, you could do like so:
let headers: HTTPHeaders? // this is an input parameter in a function for example
var customHeaders: HTTPHeaders = headers ?? [:] // nil coalescing
customHeaders["key"] = "value"
I tried this for Swift 3.1 and it worked:
if (myDict?[key] = value) == nil {
myDict = [key: value]
}

Upcasting F# record created through reflection

I've been messing about with F# and it's Reflection, trying to create a Record type object dynamically from within F#, I got most of it working (as you can see below) but one thing - the record I create through reflection has type "obj" instead the one it should ("Person") and I can't seem to be able to upcast it in any way.
#light
type Person = {
Name:string;
Age:int;
}
let example = {Name = "Fredrik"; Age = 23;}
// example has type Person = {Name = "Fredrik"; Age = 23;}
let creator = Reflection.FSharpValue.PrecomputeRecordConstructor(example.GetType(),
System.Reflection.BindingFlags.Public)
let reflected = creator [| ("thr" :> obj); (23 :> obj) |]
// here reflected will have the type obj = {Name = "thr"; Age = 23;}
// Function that changes the name of a Person record
let changeName (x:Person) (name:string) =
{ x with Name = name }
// Works with "example" which is has type "Person"
changeName example "Johan"
// But not with "reflected" since it has type "obj"
changeName reflected "Jack" // Error "This expression has type obj but is here used with type Person. "
// But casting reflected to Person doesn't work either
(reflected :> Person) // Type constraint mismatch. The type obj is not compatible with
// type Person. The type 'obj' is not compatible with the type 'Person'.
// C:\Users\thr\Documents\Visual Studio 2008\Projects\
// Reflection\Reflection\Script.fsx 34 2 Reflection
Try using the other cast operator (as you're casting the other way this time)
So changeName (reflected :?> Person) "Jack"

Resources