There are several types of data types in Go: basic (int / float / bool / string / rune / byte), composite (array / struct), and reference (slice / map / pointer / channel / function). In this section, we will execute a simple process for each data type to check its operation.
Basic Type
int
package main
import (
"fmt"
)
func main() {
var (
i1 int = 10 // signed, depends on execution architecture (32bit or 64bit)
i2 int = 1e9 // 9 to the power of 10(=1000000000)
i3 int16 = 10 // signed min:-32768 max:32767
i4 int32 = 10 // signed min:-2147483648 max:2147483647 (about 2 billion)
i5 int64 = 10 // signed min:-9223372036854775808 max:9223372036854775807
i6 uint = 10 // unsigned depends on execution architecture (32bit or 64bit)
i7 uint32 = 10 // unsigned min:0 max:4294967295 (about 4 billion)
)
fmt.Printf("%T %T %T %T %T %T %T\n", i1, i2, i3, i4, i5, i6, i7)
}
int int int16 int32 int64 uint uint32
float
package main
import (
"fmt"
)
func main() {
var (
f32 float32 = 1.11111111111111111
f64 float64 = 1.11111111111111111
)
fmt.Printf("%T\n", f32)
fmt.Println(f32)
fmt.Printf("%T\n", f64)
fmt.Println(f64)
}
float32
1.1111112
float64
1.1111111111111112
bool
package main
import (
"fmt"
)
func main() {
var (
t bool = true
f bool = false
)
fmt.Printf("%T\n", t)
fmt.Println(t)
fmt.Printf("%T\n", f)
fmt.Println(f)
}
bool
true
bool
false
string
package main
import (
"fmt"
)
func main() {
var (
s1 string = "わくわくBank" // Enclose in double quotation marks
// Here Documents (enclosed in backquotes)
s2 string = `Hello
World`
)
fmt.Printf("%T\n", s1)
fmt.Println(s1)
fmt.Println(s2)
fmt.Println(len(s1))
for i, v := range s1 {
// Using the range syntax, you can get the rune by rune.
// Each letter of the alphabet is one byte.
// Japanese is almost 3 bytes per character.
fmt.Printf("%T i:%v v:%v\n", v, i, v)
}
fmt.Printf("s[12]: %v\n", s1[12])
fmt.Printf("[]rune(s): %v\n", []rune(s1))
fmt.Printf("[]byte(s): %v\n", []byte(s1))
}
string
わくわくBank
Hello
World
16
int32 i:0 v:12431
int32 i:3 v:12367
int32 i:6 v:12431
int32 i:9 v:12367
int32 i:12 v:66
int32 i:13 v:97
int32 i:14 v:110
int32 i:15 v:107
s[12]: 66
[]rune(s): [12431 12367 12431 12367 66 97 110 107]
[]byte(s): [227 130 143 227 129 143 227 130 143 227 129 143 66 97 110 107]
rune
package main
import (
"fmt"
)
func main() {
var (
r1 rune = 97
r2 rune = 'a' // Single Quarto handles Rune type.
)
fmt.Printf("%T\n", r1)
fmt.Println(r1)
fmt.Println(string(r1))
fmt.Printf("%T\n", r2)
fmt.Println(r2)
fmt.Println(string(r2))
}
int32
97
a
int32
97
a
byte
package main
import (
"fmt"
)
func main() {
var (
b byte = 97
)
fmt.Printf("%T\n", b)
fmt.Println(b)
fmt.Println(string(b))
}
uint8
97
a
Composite Type
Array
The number of array elements is fixed. If you want to add elements, use slices.
package main
import "fmt"
func main() {
var array1 [2]string
array1[0] = "aaa"
array1[1] = "bbb"
fmt.Printf("%T\n", array1)
fmt.Println(array1[0], array1[1])
fmt.Println(array1)
fmt.Println(len(array1))
fmt.Println("-----------------------")
array2 := [4]int{1, 2, 3, 4}
fmt.Printf("%T\n", array2)
fmt.Println(array2)
fmt.Println("-----------------------")
array3 := [...]int{1, 2, 3, 4}
fmt.Printf("%T\n", array3)
fmt.Println(array3)
}
[2]string
aaa bbb
[aaa bbb]
2
-----------------------
[4]int
[1 2 3 4]
-----------------------
[4]int
[1 2 3 4]
Struct
package main
import "fmt"
type User struct {
ID int
Name string
age int // Leading lowercase letters are private
Score int
}
func main() {
u1 := User{}
fmt.Printf("%T\n", u1)
fmt.Println(u1)
u2 := User{1, "yamada", 30, 100}
fmt.Printf("%T\n", u2)
fmt.Println(u2)
u2.Name = "suzuki"
u2.age = 31 // Can be updated from the same package
fmt.Println(u2)
// Update value via structure pointer
p := &u2
p.age = 32
fmt.Printf("%T\n", p)
fmt.Println(p)
fmt.Println(u2)
}
main.User
{0 0 0}
main.User
{1 yamada 30 100}
{1 suzuki 31 100}
*main.User
&{1 suzuki 32 100}
{1 suzuki 32 100}
Reference Type
Slice
When cap (capacity=capacity)
changes occur, memory space is reclaimed, which increases processing costs.
package main
import "fmt"
func main() {
s1 := []int{1, 2, 3, 4, 5, 6, 7, 8}
fmt.Printf("type: %T\n", s1)
fmt.Printf("len:%d cap:%d v:%v\n", len(s1), cap(s1), s1)
s1 = s1[:0]
fmt.Printf("len:%d cap:%d v:%v\n", len(s1), cap(s1), s1)
s1 = s1[:2]
fmt.Printf("len:%d cap:%d v:%v\n", len(s1), cap(s1), s1)
s1 = s1[:4]
fmt.Printf("len:%d cap:%d v:%v\n", len(s1), cap(s1), s1)
s1 = s1[2:]
fmt.Printf("len:%d cap:%d v:%v\n", len(s1), cap(s1), s1)
s1 = s1[:4]
fmt.Printf("len:%d cap:%d v:%v\n", len(s1), cap(s1), s1)
s1 = append(s1, 1, 2)
fmt.Printf("len:%d cap:%d v:%v\n", len(s1), cap(s1), s1)
s1 = append(s1, 3)
fmt.Printf("len:%d cap:%d v:%v\n", len(s1), cap(s1), s1)
fmt.Println("----------------------------------------")
// Generate slice by make
s2 := make([]int, 5, 10)
fmt.Printf("type: %T\n", s2)
fmt.Printf("len:%d cap:%d v:%v\n", len(s2), cap(s2), s2)
fmt.Println("----------------------------------------")
s3 := make([]int, 5)
fmt.Printf("type: %T\n", s3)
fmt.Printf("len:%d cap:%d v:%v\n", len(s3), cap(s3), s3)
fmt.Println("----------------------------------------")
s4 := make([]int, 0, 10)
fmt.Printf("type: %T\n", s4)
fmt.Printf("len:%d cap:%d v:%v\n", len(s4), cap(s4), s4)
}
type: []int
len:8 cap:8 v:[1 2 3 4 5 6 7 8]
len:0 cap:8 v:[]
len:2 cap:8 v:[1 2]
len:4 cap:8 v:[1 2 3 4]
len:2 cap:6 v:[3 4]
len:4 cap:6 v:[3 4 5 6]
len:6 cap:6 v:[3 4 5 6 1 2]
len:7 cap:12 v:[3 4 5 6 1 2 3]
----------------------------------------
type: []int
len:5 cap:10 v:[0 0 0 0 0]
----------------------------------------
type: []int
len:5 cap:5 v:[0 0 0 0 0]
----------------------------------------
type: []int
len:0 cap:10 v:[]
Multidimensional Slice
package main
import "fmt"
func main() {
s1 := [][]int{
{1, 2, 3},
{1, 2, 3, 4, 5, 6, 7, 8},
}
fmt.Printf("type: %T\n", s1)
fmt.Printf("len:%d cap:%d v:%v\n", len(s1), cap(s1), s1)
s1 = append(s1, []int{1, 2})
fmt.Printf("len:%d cap:%d v:%v\n", len(s1), cap(s1), s1)
}
type: [][]int
len:2 cap:2 v:[[1 2 3] [1 2 3 4 5 6 7 8]]
len:3 cap:4 v:[[1 2 3] [1 2 3 4 5 6 7 8] [1 2]]
Map
package main
import "fmt"
func main() {
var m1 map[string]int
fmt.Printf("%T\n", m1)
fmt.Println("----------------------")
fmt.Println(m1)
// If only a var declaration is used, the content is nil.
fmt.Printf("m1 == nil: %v\n", m1 == nil)
// Setting availability can be determined by len
fmt.Printf("len(m1): %v\n", len(m1))
fmt.Println("----------------------")
// Using make takes up memory space.
m1 = make(map[string]int)
fmt.Println(m1)
fmt.Printf("m1 == nil: %v\n", m1 == nil)
fmt.Printf("len(m1): %v\n", len(m1))
fmt.Println("----------------------")
m1["aaa"] = 1
m1["bbb"] = 2
m1["ccc"] = 3
fmt.Println(m1)
fmt.Printf("len(m1): %v\n", len(m1))
fmt.Println("----------------------")
delete(m1, "bbb")
fmt.Println(m1)
fmt.Println("----------------------")
_, ok1 := m1["bbb"]
fmt.Println(ok1)
_, ok2 := m1["ccc"]
fmt.Println(ok2)
}
map[string]int
----------------------
map[]
m1 == nil: true
len(m1): 0
----------------------
map[]
m1 == nil: false
len(m1): 0
----------------------
map[aaa:1 bbb:2 ccc:3]
len(m1): 3
----------------------
map[aaa:1 ccc:3]
----------------------
false
true
Combination notes for Map and Struct ( Cannot assign to xxx )
When Struct is stored in Map, it is not possible to update the elements of Struct while it is stored in Map.
package main
import "fmt"
type sampleStruct struct {
x int
}
func main() {
sampleMap := make(map[int]sampleStruct, 1)
sampleMap[0] = sampleStruct{x: 100}
// sampleMap[0].x: 100
fmt.Printf("sampleMap[0].x: %d\n", sampleMap[0].x)
// The following is "Cannot assign to sampleMap[0].x".
// sampleMap[0].x = 200
// It must be taken out once as follows
sm := sampleMap[0]
sm.x = 200
sampleMap[0] = sm
// sampleMap[0].x: 200
fmt.Printf("sampleMap[0].x: %d\n", sampleMap[0].x)
}
Multidimensional Map
package main
import "fmt"
func main() {
var m2 map[string]map[string]int
m2 = make(map[string]map[string]int)
fmt.Printf("%T\n", m2)
fmt.Println(m2)
fmt.Println("----------------------")
// The following error occurs (panic: assignment to entry in nil map). Because m2["aaa"] is nil.
// m2["aaa"]["xxx"] = 1
if _, ok := m2["aaa"]; !ok {
m2["aaa"] = make(map[string]int)
m2["aaa"]["xxx"] = 1
m2["aaa"]["yyy"] = 2
m2["aaa"]["zzz"] = 3
}
fmt.Println(m2)
}
map[string]map[string]int
map[]
----------------------
map[aaa:map[xxx:1 yyy:2 zzz:3]]
We also see alternative methods such as using a concatenated string of key strings as the key to avoid a multidimensional map.
Pointer
package main
import "fmt"
func main() {
var p *int // Pointer type pointing to int.
fmt.Printf("%T\n", p)
fmt.Println(p)
i := 100
p = &i
fmt.Println("-----------------------")
fmt.Println(p)
fmt.Println(*p)
fmt.Println(i)
fmt.Println(&i)
*p = 200
fmt.Println("-----------------------")
fmt.Println(p)
fmt.Println(*p)
fmt.Println(i)
fmt.Println(&i)
i = 300
fmt.Println("-----------------------")
fmt.Println(p)
fmt.Println(*p)
fmt.Println(i)
fmt.Println(&i)
}
*int
<nil>
-----------------------
0xc0000160a0
100
100
0xc0000160a0
-----------------------
0xc0000160a0
200
200
0xc0000160a0
-----------------------
0xc0000160a0
300
300
0xc0000160a0
Channel
Channel
can be utilized to exchange data with functions running concurrently in goroutine.
package main
import (
"fmt"
"sync"
"time"
)
// <-chan int: read only
func receivePrint(name string, c <-chan int, wg *sync.WaitGroup) {
for {
time.Sleep(1000 * time.Millisecond)
i, ok := <-c
fmt.Printf("[Receive]\tname: %v\tcap: %v\tlen: %v\ti: %v\tok: %v\n", name, cap(c), len(c), i, ok)
if ok == false {
break
}
}
fmt.Printf("[Done]\t\tname: %v\n", name)
wg.Done()
}
func main() {
var wg sync.WaitGroup
// Channels with a buffer size of 5
c := make(chan int, 5)
fmt.Printf("%T\n", c)
fmt.Println(c)
wg.Add(2)
go receivePrint("1st", c, &wg)
go receivePrint("2nd", c, &wg)
for i := 0; i < 10; i++ {
c <- i
fmt.Printf("[Send]\t\tname: main\tcap: %v\tlen: %v\n", cap(c), len(c))
}
close(c)
wg.Wait()
fmt.Println("[Done]\t\tname: main")
}
chan int
0xc000112000
[Send] name: main cap: 5 len: 1
[Send] name: main cap: 5 len: 2
[Send] name: main cap: 5 len: 3
[Send] name: main cap: 5 len: 4
[Send] name: main cap: 5 len: 5
[Send] name: main cap: 5 len: 4
[Send] name: main cap: 5 len: 5
[Receive] name: 1st cap: 5 len: 4 i: 1 ok: true
[Receive] name: 2nd cap: 5 len: 5 i: 0 ok: true
[Receive] name: 2nd cap: 5 len: 5 i: 2 ok: true
[Send] name: main cap: 5 len: 4
[Send] name: main cap: 5 len: 5
[Receive] name: 1st cap: 5 len: 4 i: 3 ok: true
[Receive] name: 2nd cap: 5 len: 5 i: 4 ok: true
[Receive] name: 1st cap: 5 len: 4 i: 5 ok: true
[Send] name: main cap: 5 len: 4
[Receive] name: 1st cap: 5 len: 3 i: 6 ok: true
[Receive] name: 2nd cap: 5 len: 2 i: 7 ok: true
[Receive] name: 2nd cap: 5 len: 1 i: 8 ok: true
[Receive] name: 1st cap: 5 len: 0 i: 9 ok: true
[Receive] name: 2nd cap: 5 len: 0 i: 0 ok: false
[Done] name: 2nd
[Receive] name: 1st cap: 5 len: 0 i: 0 ok: false
[Done] name: 1st
[Done] name: main
Function
package main
import "fmt"
func main() {
f := func(x int) {
fmt.Println("hello world '", x, "'.")
}
f(1)
fmt.Printf("%T\n", f)
fmt.Println(f)
}
hello world ' 1 '.
func(int)
0x10a8b80
interface{}
interface{}
is a type compatible with any type.
package main
import (
"fmt"
)
func printInterface(i interface{}) {
fmt.Printf("%v[%T]\n", i, i)
switch v := i.(type) {
case int:
fmt.Printf("%v is int[%T]\n", v, v)
case string:
fmt.Printf("%v is string[%T]\n", v, v)
default:
fmt.Printf("default: %v[%T]\n", v, v)
}
}
func main() {
var i interface{}
fmt.Printf("%v[%T]\n", i, i)
fmt.Println("-----------------------------")
i = "hello"
fmt.Printf("%v[%T]\n", i, i)
printInterface(i)
fmt.Println("-----------------------------")
i = 100
fmt.Printf("%v[%T]\n", i, i)
printInterface(i)
fmt.Println("-----------------------------")
i = true
fmt.Printf("%v[%T]\n", i, i)
printInterface(i)
}
<nil>[<nil>]
-----------------------------
hello[string]
hello[string]
hello is string[string]
-----------------------------
100[int]
100[int]
100 is int[int]
-----------------------------
true[bool]
true[bool]
default: true[bool]
Type Conversion
Type Cast
package main
import "fmt"
func main() {
// int → float64
var i1 int = 1
var f1 float64 = float64(i1)
// i1: 1(int) f1: 1(float64)
fmt.Printf("i1: %v(%T) f1: %v(%T)\n", i1, i1, f1, f1)
// float64 → int
var f2 float64 = 1.11111
var i2 int = int(f2)
// i2: 1(int) f2: 1.11111(float64)
fmt.Printf("i2: %v(%T) f2: %v(%T)\n", i2, i2, f2, f2)
}
Type Cast(Pointer)
Casts MyInt to int.
package main
import "fmt"
func main() {
type MyInt int
i1 := MyInt(1)
var i2 *int
i2 = (*int)(&i1)
fmt.Printf("i1: %v(%T) &i1: %v(%T)\n", i1, i1, &i1, &i1)
fmt.Printf("i2: %v(%T) *i2: %v(%T)\n", i2, i2, *i2, *i2)
*i2 = 100
fmt.Printf("i1: %v(%T) &i1: %v(%T)\n", i1, i1, &i1, &i1)
fmt.Printf("i2: %v(%T) *i2: %v(%T)\n", i2, i2, *i2, *i2)
}
i1: 1(main.MyInt) &i1: 0xc0000160a0(*main.MyInt)
i2: 0xc0000160a0(*int) *i2: 1(int)
i1: 100(main.MyInt) &i1: 0xc0000160a0(*main.MyInt)
i2: 0xc0000160a0(*int) *i2: 100(int)
Since it is a pointer, updating i2 also changes the value of i1.
strconv.Atoi, strconv.ItoA
Convert between string and int using strconv.
package main
import (
"fmt"
"strconv"
)
func main() {
// string → int
s1 := "999"
i1, _ := strconv.Atoi(s1)
// s1: 999(string) i1: 999(int)
fmt.Printf("s1: %v(%T) i1: %v(%T)\n", s1, s1, i1, i1)
// int → string
i2 := 999
s2 := strconv.Itoa(i2)
// s2: 999(string) i2: 999(int)
fmt.Printf("s2: %v(%T) i2: %v(%T)\n", s2, s2, i2, i2)
}