Assignment between custom slice type and the underlying type - go

Go assignment shows error for int but not for []int slice.
working code here
package main
import (
"fmt"
)
type testType []int
func main() {
var i testType
var t []int
t = i
fmt.Println("Hello, playground", t, i)
}
However, if it is int type the compiler will surely show errors here:
cannot use i (type testType) as type int in assignment
package main
import (
"fmt"
)
type testType int
func main() {
var i testType
var t int
t = i
fmt.Println("Hello, playground", t, i)
}
Why does it error out for the custom int type and not the custom []int type?

It is defined in Go language specification for assignment types:
A value x is assignable to a variable of type T ("x is assignable to
T") if one of the following conditions applies:
x's type is identical to T.
x's type V and T have identical underlying types and at least one of V or T is not a defined type.
T is an interface type and x implements T.
x is a bidirectional channel value, T is a channel type, x's type V and T have identical element types, and at least one of V or T is
not a defined type.
x is the predeclared identifier nil and T is a pointer, function, slice, map, channel, or interface type.
x is an untyped constant representable by a value of type T.
In your case []int is a slice and not named type. That's why the compiler did not complain. For more information on named types go through Go specification for types:
A type determines the set of values and operations specific to values
of that type. Types may be named or unnamed. Named types are specified
by a (possibly qualified) type name; unnamed types are specified using
a type literal, which composes a new type from existing types.

Related

Go type definition and initialize a pointer [duplicate]

I am using custom types and I have a problem when pointers are involved like below.
Code below is valid:
package main
import (
"fmt"
)
type deck []string
func newDeck(cards ...string) deck {
return cards
}
Code below is valid too:
package main
func str(n []string) *[]string {
return &n
}
The below code instead is not valid. Why so? I have to write a type conversion like return (*deck)(&cards)
package main
import (
"fmt"
)
type deck []string
func newDeck(cards ...string) *deck {
return &cards // compiles with return (*deck)(&cards)
}
The rules about assignments (including returns) are defined in the Go specs: Assignability. The one that is relevant to your case is:
V and T have identical underlying types and at least one of V or T is not a named type.
And Underlying types:
If T is one of the predeclared boolean, numeric, or string types, or a type literal, the corresponding underlying type is T itself.
The first example compiles because []string is an unnamed type literal with underlying type []string (itself) and deck is a named type with underlying type []string (by your type definition).
The second example does not compile because both *[]string and *deck are unnamed type literals with themselves as (different) underlying types.
To make the second example compile, you can't rely on a direct assignment, but, as you found out, use an explicit type conversion
return (*deck)(&cards)
And this conversion is valid due to the following rule:
ignoring struct tags (see below), x's type and T are pointer types that are not named types, and their pointer base types are not type parameters but have identical underlying types.

What are built-in types(or non-defined types) in GoLang?

Spec says:
A value x is assignable to a variable of type T ("x is assignable to T") if one of the following conditions applies:
x's type V and T have identical underlying types and at least one of V or T is not a defined type.
numerical type uint8 is a defined type, so with the above rule, assignability fails in the below code:
package main
type Point struct {
x uint8
y uint8
}
type Polar Point
var p Polar = Point{x: 1, y: 2}
func main() {
}
What are non-defined types in GoLang, to test the above rule?
A non-defined type is a type without an identifier assigned to them. For instance:
type S struct {
A int
}
func main() {
var s S
// You can assign a literal struct with the same underlying type to a variable of type S
s=struct{A int}{1}
}
Above, the type of struct {A int} is not a defined type.
// The underlying types of the following ones are both int.
type (
MyInt int
Age MyInt
)
// The following new types have different underlying types.
type (
IntSlice []int // underlying type is []int
MyIntSlice []MyInt // underlying type is []MyInt
AgeSlice []Age // underlying type is []Age
)
// The underlying types of []Age, Ages, and AgeSlice
// are all the non-defined type []Age.
type Ages AgeSlice
Type System Overview

how to use a derived type for sync.Map

My goal is to have a custom type the one I could derive and add extra methods, for example, when using a map this works:
package main
import "fmt"
type myMap map[string]string
func (m *myMap) Add() {
_, ok := (*m)["test"]
println(ok)
}
func main() {
x := &myMap{}
fmt.Printf("x = %+v\n", x)
}
But if want the same with sync.Map how to do it? I am currently trying this: https://play.golang.org/p/8PjpPY-Sjq
package main
import (
"fmt"
"sync"
)
type myMap sync.Map
func (m *myMap) Add() {
_, ok := (*m).Load("test")
println(ok)
}
func main() {
x := &myMap{}
fmt.Printf("x = %+v\n", x)
}
But get this error:
(*m).Load undefined (type myMap has no field or method Load)
Any ideas?
The Go Programming Language Specification
Struct types
A struct is a sequence of named elements, called fields, each of
which has a name and a type. Field names may be specified explicitly
(IdentifierList) or implicitly (EmbeddedField). Within a struct,
non-blank field names must be unique.
StructType = "struct" "{" { FieldDecl ";" } "}" .
FieldDecl = (IdentifierList Type | EmbeddedField) [ Tag ] .
EmbeddedField = [ "*" ] TypeName .
Tag = string_lit .
A field declared with a type but no explicit field name is called an
embedded field. An embedded field 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.
A field or method f of an embedded field in a struct x is called
promoted if x.f is a legal selector that denotes that field or method
f.
Promoted fields act like ordinary fields of a struct except that they
cannot be used as field names in composite literals of the struct.
Given a struct type S and a type named T, promoted methods are
included in the method set of the struct as follows:
If S contains an embedded field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S
also includes promoted methods with receiver *T.
If S contains an embedded field *T, the method sets of S and *S both include promoted methods with receiver T or *T.
Use an embedded field of a struct. For example,
package main
import (
"fmt"
"sync"
)
type myMap struct {
sync.Map
}
func (m *myMap) Add(key, value interface{}) bool {
_, loaded := m.LoadOrStore(key, value)
return !loaded
}
func main() {
x := &myMap{}
k := "test"
ok := x.Add(k, 42)
fmt.Println(ok)
v, ok := x.Load(k)
fmt.Println(k, v, ok)
}
Playground: https://play.golang.org/p/YCNeiYVhlT
Output:
true
test 42 true
The Go Programming Language Specification
Selectors
For a primary expression x that is not a package name, the selector
expression
x.f
denotes the field or method f of the value x (or sometimes *x; see
below). The identifier f is called the (field or method) selector; it
must not be the blank identifier. The type of the selector expression
is the type of f. If x is a package name, see the section on qualified
identifiers.
A selector f may denote a field or method f of a type T, or it may
refer to a field or method f of a nested embedded field of T. The
number of embedded fields traversed to reach f is called its depth in
T. The depth of a field or method f declared in T is zero. The depth
of a field or method f declared in an embedded field A in T is the
depth of f in A plus one.
Rule 1:
For a value x of type T or *T where T is not a pointer or interface
type, x.f denotes the field or method at the shallowest depth in T
where there is such an f. If there is not exactly one f with
shallowest depth, the selector expression is illegal.
Sometimes, there is ambiguity in complex cases of nested embedding. If so, specify the full qualifiers explicitly. For example, m.Map.LoadOrStore and x.Map.Load.
package main
import (
"fmt"
"sync"
)
type myMap struct {
sync.Map
}
func (m *myMap) Add(key, value interface{}) bool {
_, loaded := m.Map.LoadOrStore(key, value)
return !loaded
}
func main() {
x := &myMap{}
k := "test"
ok := x.Add(k, 42)
fmt.Println(ok)
v, ok := x.Map.Load(k)
fmt.Println(k, v, ok)
}
The line: type myMap sync.Map defines a new type based on an existing type.
According to the Language Specification:
A defined type may have methods associated with it. It does not
inherit any methods bound to the given type
It means, that myMap only inherits the fields of sync.Map (which is a struct) but not it's methods. It doesn't work like class inheritance in other languages.
Specifically, sync.Map does not have any exported fields, so using it to define a new type is pointless.
Instead you should define a struct type that contains sync.Map as a field. Then you'll have access to it's methods. #peterSO's answer shows how to do that.

How can I return a subtype of the specified return value (in this case interface{})?

I have an interface that defines one parameter to have type func(interface{}, proto.Message) interface{} and I'm trying to pass something of type func reduceMsg(a interface{}, b proto.Message) []*PersistentData to it. This results in the following compiler error:
Cannot use reduceMsg (type func(a interface{}, b proto.Message) []*PersistentData as type func(interface{}, proto.Message) interface{}
What is the reason for this error, and how can I work around it? It seems like returning a more specific type than interface{} should be legal. Here's a simple complete example that illustrates the issue:
package main
import "fmt"
func main() {
var t func() interface{} = func() []string { return []string{} }
fmt.Println(t)
}
The type of the object is the whole function signature. If the signature don't match, then it's not the same type and can't be assigned that way.
Anything can be assigned to the empty interface, because all types satisfy the interface, but in your problem neither type is the empty interface, you just have a function that returns an empty interface.
Not because a part of the function can be assigned to another it makes it the same. The type is the whole function signature. I think it's the same logic behind not being able to assign an int to an int8. You can cast them if you want, but for go, they are separate types and you need to deal with making the necessary conversions to be able to assign them.
What you can do is change your second function signature to return an empty interface like this:
func(interface{}, proto.Message) interface{}
func reduceMsg(a interface{}, b proto.Message) interface{} {
var a []*PersistentData
// do something here
return a
}
This way the function signature is the same, so it's consider the same type and you are returning an []*PersistentData. Of course you will need to do a type assertion before using it as such because the program will treat it as an {}interface because that is the type that the function returned.
Referencing the spec,
In assignments, each value must be assignable to the type of the operand to which it is assigned, with the following special cases:
Any typed value may be assigned to the blank identifier.
If an untyped constant is assigned to a variable of interface type or the blank identifier, the constant is first converted to its default type.
If an untyped boolean value is assigned to a variable of interface type or the blank identifier, it is first converted to type bool.
Assignability
A value x is assignable to a variable of type T ("x is assignable to T") in any of these cases:
x's type is identical to T.
x's type V and T have identical underlying types and at least one of V or T is not a named type.
T is an interface type and x implements T.
x is a bidirectional channel value, T is a channel type, x's type V and T have identical element types, and at least one of V or T is not a named type.
x is the predeclared identifier nil and T is a pointer, function, slice, map, channel, or interface type.
x is an untyped constant representable by a value of type T.
In general, Go doesn't allow you to implicitly convert values from one type to another, with the exception of being able to use concrete-typed objects as though they were interfaces (that they implement).
In this particular case, since your function doesn't actually return an interface{}, the compiler would have to do some extra work to wrap up the return value as an interface{} and return it; if you really want to accomplish what you're trying you can do this explicitly yourself:
type Foo struct {
X int
}
func create(x int) Foo {
return Foo{X: x}
}
func main() {
var f func(int) interface{} = func(x int) interface{} {
return create(x)
}
}
which is basically doing (explicitly) the wrapping operation that you want the runtime to do implicitly.

Go type automatically converting when it seems like it shouldn't

Sorry for the ambiguous title. I'm not getting a compiler error when I believe that I should, based on creating a new type and a function that takes an argument of that type.
The example:
package search
//Some random type alias
type Search string
//Takes a string and returns Search
func NewSearch(s string) Search {
return Search(s)
}
//This is where things are getting weird
//Returns an int just for arbitrary testing
func PrintSearch(s Search) int{
return 5
}
Now my assumption would be, if I created an object using NewSearch, I would be able to pass it to PrintSearch and have everything run as expected, but if I passed PrintSearch a primitive string, it should not compile. I am not experiencing this behavior.
The main code:
package main
import (
"fmt"
".../search" //no need to type the whole path here
)
func main() {
SearchTerm := search.NewSearch("Test")
StringTerm := "Another test"
fmt.Println(search.PrintSearch(SearchTerm)) // This should print 5
fmt.Println(search.PrintSearch(StringTerm)) // This should throw a compiler error, but it is not
}
It seems like if I write the type and the function in the same package as main, everything works as I'd expect? As in, it throws a compiler error. Is there something I've missed about cross-package type coercion?
We can simplify this example a bit further (playground):
package main
type Foo string
type Bar int
func main() {
var f Foo = "foo"
var b Bar = 1
println(f, b)
}
This is explained in the spec's assignability section.
A value x is assignable to a variable of type T ("x is assignable to
T") in any of these cases:
x's type is identical to T.
x's type V and T have identical underlying types and at least one of V or T is not a named type.
T is an interface type and x implements T.
x is a bidirectional channel value, T is a channel type, x's type V and T have identical element types, and at least one of V or T is not a named type.
x is the predeclared identifier nil and T is a pointer, function, slice, map, channel, or interface type.
x is an untyped constant representable by a value of type T.

Resources