Исходники и презентации

This commit is contained in:
2025-05-23 07:26:39 +03:00
parent aa948179d5
commit 02d8430a3a
514 changed files with 13773 additions and 0 deletions

View File

@ -1 +1,14 @@
# deep_go # deep_go
- Модуль 1 «Основные типы данных»
- Модуль 2 «Массивы и срезы»
- Модуль 3 «Строки»
- Модуль 4 «Словари»
- Модуль 5 «Функции»
- Модуль 6 «Структуры»
- Модуль 7 «Интерфейсы»
- Модуль 8 «Обработка ошибок»
- Модуль 9 «Дженерики и рефлексия»
- Модуль 10 «Аллокатор»
- Модуль 11 «Сборщик мусора»
- Модуль 12 «Горутины и планировщик Go»

14
go.mod Normal file
View File

@ -0,0 +1,14 @@
module golang_course
go 1.22
require (
github.com/stretchr/testify v1.9.0
golang.org/x/text v0.18.0
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

12
go.sum Normal file
View File

@ -0,0 +1,12 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -0,0 +1,49 @@
package main
import (
"reflect"
"testing"
"unsafe"
"github.com/stretchr/testify/assert"
)
// go test -v homework_test.go
func Defragment(memory []byte, pointers []unsafe.Pointer) {
// need to implement
}
func TestDefragmentation(t *testing.T) {
var fragmentedMemory = []byte{
0xFF, 0x00, 0x00, 0x00,
0x00, 0xFF, 0x00, 0x00,
0x00, 0x00, 0xFF, 0x00,
0x00, 0x00, 0x00, 0xFF,
}
var fragmentedPointers = []unsafe.Pointer{
unsafe.Pointer(&fragmentedMemory[0]),
unsafe.Pointer(&fragmentedMemory[5]),
unsafe.Pointer(&fragmentedMemory[10]),
unsafe.Pointer(&fragmentedMemory[15]),
}
var defragmentedPointers = []unsafe.Pointer{
unsafe.Pointer(&fragmentedMemory[0]),
unsafe.Pointer(&fragmentedMemory[1]),
unsafe.Pointer(&fragmentedMemory[2]),
unsafe.Pointer(&fragmentedMemory[3]),
}
var defragmentedMemory = []byte{
0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
}
Defragment(fragmentedMemory, fragmentedPointers)
assert.True(t, reflect.DeepEqual(defragmentedMemory, fragmentedMemory))
assert.True(t, reflect.DeepEqual(defragmentedPointers, fragmentedPointers))
}

View File

@ -0,0 +1,58 @@
package main
import (
"sync/atomic"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
// go test -v homework_test.go
type WorkerPool struct {
// need to implement
}
func NewWorkerPool(workersNumber int) *WorkerPool {
// need to implement
return &WorkerPool{}
}
// Return an error if the pool is full
func (wp *WorkerPool) AddTask(task func()) error {
// need to implement
return nil
}
// Shutdown all workers and wait for all
// tasks in the pool to complete
func (wp *WorkerPool) Shutdown() {
// need to implement
}
func TestWorkerPool(t *testing.T) {
var counter atomic.Int32
task := func() {
time.Sleep(time.Millisecond * 500)
counter.Add(1)
}
pool := NewWorkerPool(2)
_ = pool.AddTask(task)
_ = pool.AddTask(task)
_ = pool.AddTask(task)
time.Sleep(time.Millisecond * 600)
assert.Equal(t, int32(2), counter.Load())
time.Sleep(time.Millisecond * 600)
assert.Equal(t, int32(3), counter.Load())
_ = pool.AddTask(task)
_ = pool.AddTask(task)
_ = pool.AddTask(task)
pool.Shutdown() // wait tasks
assert.Equal(t, int32(6), counter.Load())
}

View File

@ -0,0 +1,74 @@
package main
import (
"context"
"errors"
"sync/atomic"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
type Group struct {
// need to implement
}
func NewErrGroup(ctx context.Context) (*Group, context.Context) {
// need to implement
return &Group{}, ctx
}
func (g *Group) Go(action func() error) {
// need to implement
}
func (g *Group) Wait() error {
// need to implement
return nil
}
func TestErrGroupWithoutError(t *testing.T) {
var counter atomic.Int32
group, _ := NewErrGroup(context.Background())
for i := 0; i < 5; i++ {
group.Go(func() error {
time.Sleep(time.Second)
counter.Add(1)
return nil
})
}
err := group.Wait()
assert.Equal(t, int32(5), counter.Load())
assert.NoError(t, err)
}
func TestErrGroupWithError(t *testing.T) {
var counter atomic.Int32
group, ctx := NewErrGroup(context.Background())
for i := 0; i < 5; i++ {
group.Go(func() error {
timer := time.NewTimer(time.Second)
defer timer.Stop()
select {
case <-ctx.Done():
return ctx.Err()
case <-timer.C:
counter.Add(1)
return nil
}
})
}
group.Go(func() error {
return errors.New("error")
})
err := group.Wait()
assert.Equal(t, int32(0), counter.Load())
assert.Error(t, err)
}

View File

@ -0,0 +1,48 @@
package main
import (
"testing"
"github.com/stretchr/testify/assert"
)
// go test -v homework_test.go
func ToLittleEndian(number uint32) uint32 {
return 0 // need to implement
}
func TestСonversion(t *testing.T) {
tests := map[string]struct {
number uint32
result uint32
}{
"test case #1": {
number: 0x00000000,
result: 0x00000000,
},
"test case #2": {
number: 0xFFFFFFFF,
result: 0xFFFFFFFF,
},
"test case #3": {
number: 0x00FF00FF,
result: 0xFF00FF00,
},
"test case #4": {
number: 0x0000FFFF,
result: 0xFFFF0000,
},
"test case #5": {
number: 0x01020304,
result: 0x04030201,
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
result := ToLittleEndian(test.number)
assert.Equal(t, test.result, result)
})
}
}

View File

@ -0,0 +1,33 @@
package main
import (
"errors"
"testing"
"github.com/stretchr/testify/assert"
)
// go test -v homework_test.go
type MultiError struct {
// need to implement
}
func (e *MultiError) Error() string {
// need to implement
return ""
}
func Append(err error, errs ...error) *MultiError {
// need to implement
return nil
}
func TestMultiError(t *testing.T) {
var err error
err = Append(err, errors.New("error 1"))
err = Append(err, errors.New("error 2"))
expectedMessage := "2 errors occured:\n\t* error 1\t* error 2\n"
assert.EqualError(t, err, expectedMessage)
}

View File

@ -0,0 +1,150 @@
package main
import (
"reflect"
"testing"
"github.com/stretchr/testify/assert"
)
func Map(data []int, action func(int) int) []int {
// need to implement
return nil
}
func Filter(data []int, action func(int) bool) []int {
// need to implement
return nil
}
func Reduce(data []int, initial int, action func(int, int) int) int {
// need to implement
return 0
}
func TestMap(t *testing.T) {
tests := map[string]struct {
data []int
action func(int) int
result []int
}{
"nil numbers": {
action: func(number int) int {
return -number
},
},
"empty numbers": {
data: []int{},
action: func(number int) int {
return -number
},
result: []int{},
},
"inc numbers": {
data: []int{1, 2, 3, 4, 5},
action: func(number int) int {
return number + 1
},
result: []int{2, 3, 4, 5, 6},
},
"double numbers": {
data: []int{1, 2, 3, 4, 5},
action: func(number int) int {
return number * number
},
result: []int{1, 4, 9, 16, 25},
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
result := Map(test.data, test.action)
assert.True(t, reflect.DeepEqual(test.result, result))
})
}
}
func TestFilter(t *testing.T) {
tests := map[string]struct {
data []int
action func(int) bool
result []int
}{
"nil numbers": {
action: func(number int) bool {
return number == 0
},
},
"empty numbers": {
data: []int{},
action: func(number int) bool {
return number == 1
},
result: []int{},
},
"even numbers": {
data: []int{1, 2, 3, 4, 5},
action: func(number int) bool {
return number%2 == 0
},
result: []int{2, 4},
},
"positive numbers": {
data: []int{-1, -2, 1, 2},
action: func(number int) bool {
return number > 0
},
result: []int{1, 2},
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
result := Filter(test.data, test.action)
assert.True(t, reflect.DeepEqual(test.result, result))
})
}
}
func TestReduce(t *testing.T) {
tests := map[string]struct {
initial int
data []int
action func(int, int) int
result int
}{
"nil numbers": {
action: func(lhs, rhs int) int {
return 0
},
},
"empty numbers": {
data: []int{},
action: func(lhs, rhs int) int {
return 0
},
},
"sum of numbers": {
data: []int{1, 2, 3, 4, 5},
action: func(lhs, rhs int) int {
return lhs + rhs
},
result: 15,
},
"sum of numbers with initial value": {
initial: 10,
data: []int{1, 2, 3, 4, 5},
action: func(lhs, rhs int) int {
return lhs + rhs
},
result: 25,
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
result := Reduce(test.data, test.initial, test.action)
assert.Equal(t, test.result, result)
})
}
}

View File

@ -0,0 +1,62 @@
package main
import (
"reflect"
"testing"
"unsafe"
"github.com/stretchr/testify/assert"
)
// go test -v homework_test.go
func Trace(stacks [][]uintptr) []uintptr {
// need to implement
return nil
}
func TestTrace(t *testing.T) {
var heapObjects = []int{
0x00, 0x00, 0x00, 0x00, 0x00,
}
var heapPointer1 *int = &heapObjects[1]
var heapPointer2 *int = &heapObjects[2]
var heapPointer3 *int = nil
var heapPointer4 **int = &heapPointer3
var stacks = [][]uintptr{
{
uintptr(unsafe.Pointer(&heapPointer1)), 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, uintptr(unsafe.Pointer(&heapObjects[0])),
0x00, 0x00, 0x00, 0x00,
},
{
uintptr(unsafe.Pointer(&heapPointer2)), 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, uintptr(unsafe.Pointer(&heapObjects[1])),
0x00, 0x00, 0x00, uintptr(unsafe.Pointer(&heapObjects[2])),
uintptr(unsafe.Pointer(&heapPointer4)), 0x00, 0x00, 0x00,
},
{
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, uintptr(unsafe.Pointer(&heapObjects[3])),
},
}
pointers := Trace(stacks)
expectedPointers := []uintptr{
uintptr(unsafe.Pointer(&heapPointer1)),
uintptr(unsafe.Pointer(&heapObjects[0])),
uintptr(unsafe.Pointer(&heapPointer2)),
uintptr(unsafe.Pointer(&heapObjects[1])),
uintptr(unsafe.Pointer(&heapObjects[2])),
uintptr(unsafe.Pointer(&heapPointer4)),
uintptr(unsafe.Pointer(&heapPointer3)),
uintptr(unsafe.Pointer(&heapObjects[3])),
}
assert.True(t, reflect.DeepEqual(expectedPointers, pointers))
}

View File

@ -0,0 +1,56 @@
package main
import (
"testing"
"github.com/stretchr/testify/assert"
)
// go test -v homework_test.go
type Person struct {
Name string `properties:"name"`
Address string `properties:"address,omitempty"`
Age int `properties:"age"`
Married bool `properties:"married"`
}
func Serialize(person Person) string {
// need to implement
return ""
}
func TestSerialization(t *testing.T) {
tests := map[string]struct {
person Person
result string
}{
"test case with empty fields": {
result: "name=\nage=0\nmarried=false",
},
"test case with fields": {
person: Person{
Name: "John Doe",
Age: 30,
Married: true,
},
result: "name=John Doe\nage=30\nmarried=true",
},
"test case with omitempty field": {
person: Person{
Name: "John Doe",
Age: 30,
Married: true,
Address: "Paris",
},
result: "name=John Doe\naddress=Paris\nage=30\nmarried=true",
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
result := Serialize(test.person)
assert.Equal(t, test.result, result)
})
}
}

View File

@ -0,0 +1,63 @@
package main
import (
"testing"
"github.com/stretchr/testify/assert"
)
type Task struct {
Identifier int
Priority int
}
type Scheduler struct {
// need to implement
}
func NewScheduler() Scheduler {
// need to implement
return Scheduler{}
}
func (s *Scheduler) AddTask(task Task) {
// need to implement
}
func (s *Scheduler) ChangeTaskPriority(taskID int, newPriority int) {
// need to implement
}
func (s *Scheduler) GetTask() Task {
// need to implement
return Task{}
}
func TestTrace(t *testing.T) {
task1 := Task{Identifier: 1, Priority: 10}
task2 := Task{Identifier: 2, Priority: 20}
task3 := Task{Identifier: 3, Priority: 30}
task4 := Task{Identifier: 4, Priority: 40}
task5 := Task{Identifier: 5, Priority: 50}
scheduler := NewScheduler()
scheduler.AddTask(task1)
scheduler.AddTask(task2)
scheduler.AddTask(task3)
scheduler.AddTask(task4)
scheduler.AddTask(task5)
task := scheduler.GetTask()
assert.Equal(t, task5, task)
task = scheduler.GetTask()
assert.Equal(t, task4, task)
scheduler.ChangeTaskPriority(1, 100)
task = scheduler.GetTask()
assert.Equal(t, task1, task)
task = scheduler.GetTask()
assert.Equal(t, task3, task)
}

View File

@ -0,0 +1,63 @@
package main
import (
"testing"
"github.com/stretchr/testify/assert"
)
// go test -v homework_test.go
type UserService struct {
// not need to implement
NotEmptyStruct bool
}
type MessageService struct {
// not need to implement
NotEmptyStruct bool
}
type Container struct {
// need to implement
}
func NewContainer() *Container {
// need to implement
return &Container{}
}
func (c *Container) RegisterType(name string, constructor interface{}) {
// need to implement
}
func (c *Container) Resolve(name string) (interface{}, error) {
// need to implement
return nil, nil
}
func TestDIContainer(t *testing.T) {
container := NewContainer()
container.RegisterType("UserService", func() interface{} {
return &UserService{}
})
container.RegisterType("MessageService", func() interface{} {
return &MessageService{}
})
userService1, err := container.Resolve("UserService")
assert.NoError(t, err)
userService2, err := container.Resolve("UserService")
assert.NoError(t, err)
u1 := userService1.(*UserService)
u2 := userService2.(*UserService)
assert.False(t, u1 == u2)
messageService, err := container.Resolve("MessageService")
assert.NoError(t, err)
assert.NotNil(t, messageService)
paymentService, err := container.Resolve("PaymentService")
assert.Error(t, err)
assert.Nil(t, paymentService)
}

View File

@ -0,0 +1,83 @@
package main
import (
"reflect"
"testing"
"github.com/stretchr/testify/assert"
)
// go test -v homework_test.go
type OrderedMap struct {
// need to implement
}
func NewOrderedMap() OrderedMap {
return OrderedMap{} // need to implement
}
func (m *OrderedMap) Insert(key, value int) {
// need to implement
}
func (m *OrderedMap) Erase(key int) {
// need to implement
}
func (m *OrderedMap) Contains(key int) bool {
return false // need to implement
}
func (m *OrderedMap) Size() int {
return 0 // need to implement
}
func (m *OrderedMap) ForEach(action func(int, int)) {
// need to implement
}
func TestCircularQueue(t *testing.T) {
data := NewOrderedMap()
assert.Zero(t, data.Size())
data.Insert(10, 10)
data.Insert(5, 5)
data.Insert(15, 15)
data.Insert(2, 2)
data.Insert(4, 4)
data.Insert(12, 12)
data.Insert(14, 14)
assert.Equal(t, 7, data.Size())
assert.True(t, data.Contains(4))
assert.True(t, data.Contains(12))
assert.False(t, data.Contains(3))
assert.False(t, data.Contains(13))
var keys []int
expectedKeys := []int{2, 4, 5, 10, 12, 14, 15}
data.ForEach(func(key, _ int) {
keys = append(keys, key)
})
assert.True(t, reflect.DeepEqual(expectedKeys, keys))
data.Erase(15)
data.Erase(14)
data.Erase(2)
assert.Equal(t, 4, data.Size())
assert.True(t, data.Contains(4))
assert.True(t, data.Contains(12))
assert.False(t, data.Contains(2))
assert.False(t, data.Contains(14))
keys = nil
expectedKeys = []int{4, 5, 10, 12}
data.ForEach(func(key, _ int) {
keys = append(keys, key)
})
assert.True(t, reflect.DeepEqual(expectedKeys, keys))
}

View File

@ -0,0 +1,86 @@
package main
import (
"reflect"
"testing"
"github.com/stretchr/testify/assert"
)
// go test -v homework_test.go
type CircularQueue struct {
values []int
// need to implement
}
func NewCircularQueue(size int) CircularQueue {
return CircularQueue{} // need to implement
}
func (q *CircularQueue) Push(value int) bool {
return false // need to implement
}
func (q *CircularQueue) Pop() bool {
return false // need to implement
}
func (q *CircularQueue) Front() int {
return -1 // need to implement
}
func (q *CircularQueue) Back() int {
return -1 // need to implement
}
func (q *CircularQueue) Empty() bool {
return false // need to implement
}
func (q *CircularQueue) Full() bool {
return false // need to implement
}
func TestCircularQueue(t *testing.T) {
const queueSize = 3
queue := NewCircularQueue(queueSize)
assert.True(t, queue.Empty())
assert.False(t, queue.Full())
assert.Equal(t, -1, queue.Front())
assert.Equal(t, -1, queue.Back())
assert.False(t, queue.Pop())
assert.True(t, queue.Push(1))
assert.True(t, queue.Push(2))
assert.True(t, queue.Push(3))
assert.False(t, queue.Push(4))
assert.True(t, reflect.DeepEqual([]int{1, 2, 3}, queue.values))
assert.False(t, queue.Empty())
assert.True(t, queue.Full())
assert.Equal(t, 1, queue.Front())
assert.Equal(t, 3, queue.Back())
assert.True(t, queue.Pop())
assert.False(t, queue.Empty())
assert.False(t, queue.Full())
assert.True(t, queue.Push(4))
assert.True(t, reflect.DeepEqual([]int{4, 2, 3}, queue.values))
assert.Equal(t, 2, queue.Front())
assert.Equal(t, 4, queue.Back())
assert.True(t, queue.Pop())
assert.True(t, queue.Pop())
assert.True(t, queue.Pop())
assert.False(t, queue.Pop())
assert.True(t, queue.Empty())
assert.False(t, queue.Full())
}

View File

@ -0,0 +1,74 @@
package main
import (
"reflect"
"testing"
"unsafe"
"github.com/stretchr/testify/assert"
)
type COWBuffer struct {
data []byte
refs *int
// need to implement
}
func NewCOWBuffer(data []byte) COWBuffer {
return COWBuffer{} // need to implement
}
func (b *COWBuffer) Clone() COWBuffer {
return COWBuffer{} // need to implement
}
func (b *COWBuffer) Close() {
// need to implement
}
func (b *COWBuffer) Update(index int, value byte) bool {
return false // need to implement
}
func (b *COWBuffer) String() string {
return "" // need to implement
}
func TestCOWBuffer(t *testing.T) {
data := []byte{'a', 'b', 'c', 'd'}
buffer := NewCOWBuffer(data)
defer buffer.Close()
copy1 := buffer.Clone()
copy2 := buffer.Clone()
assert.Equal(t, unsafe.SliceData(data), unsafe.SliceData(buffer.data))
assert.Equal(t, unsafe.SliceData(buffer.data), unsafe.SliceData(copy1.data))
assert.Equal(t, unsafe.SliceData(copy1.data), unsafe.SliceData(copy2.data))
assert.True(t, (*byte)(unsafe.SliceData(data)) == unsafe.StringData(buffer.String()))
assert.True(t, (*byte)(unsafe.StringData(buffer.String())) == unsafe.StringData(copy1.String()))
assert.True(t, (*byte)(unsafe.StringData(copy1.String())) == unsafe.StringData(copy2.String()))
assert.True(t, buffer.Update(0, 'g'))
assert.False(t, buffer.Update(-1, 'g'))
assert.False(t, buffer.Update(4, 'g'))
assert.True(t, reflect.DeepEqual([]byte{'g', 'b', 'c', 'd'}, buffer.data))
assert.True(t, reflect.DeepEqual([]byte{'a', 'b', 'c', 'd'}, copy1.data))
assert.True(t, reflect.DeepEqual([]byte{'a', 'b', 'c', 'd'}, copy2.data))
assert.NotEqual(t, unsafe.SliceData(buffer.data), unsafe.SliceData(copy1.data))
assert.Equal(t, unsafe.SliceData(copy1.data), unsafe.SliceData(copy2.data))
copy1.Close()
previous := copy2.data
copy2.Update(0, 'f')
current := copy2.data
// 1 reference - don't need to copy buffer during update
assert.Equal(t, unsafe.SliceData(previous), unsafe.SliceData(current))
copy2.Close()
}

View File

@ -0,0 +1,226 @@
package main
import (
"math"
"testing"
"unsafe"
"github.com/stretchr/testify/assert"
)
type Option func(*GamePerson)
func WithName(name string) func(*GamePerson) {
return func(person *GamePerson) {
// need to implement
}
}
func WithCoordinates(x, y, z int) func(*GamePerson) {
return func(person *GamePerson) {
// need to implement
}
}
func WithGold(gold int) func(*GamePerson) {
return func(person *GamePerson) {
// need to implement
}
}
func WithMana(mana int) func(*GamePerson) {
return func(person *GamePerson) {
// need to implement
}
}
func WithHealth(health int) func(*GamePerson) {
return func(person *GamePerson) {
// need to implement
}
}
func WithRespect(respect int) func(*GamePerson) {
return func(person *GamePerson) {
// need to implement
}
}
func WithStrength(strength int) func(*GamePerson) {
return func(person *GamePerson) {
// need to implement
}
}
func WithExperience(experience int) func(*GamePerson) {
return func(person *GamePerson) {
// need to implement
}
}
func WithLevel(level int) func(*GamePerson) {
return func(person *GamePerson) {
// need to implement
}
}
func WithHouse() func(*GamePerson) {
return func(person *GamePerson) {
// need to implement
}
}
func WithGun() func(*GamePerson) {
return func(person *GamePerson) {
// need to implement
}
}
func WithFamily() func(*GamePerson) {
return func(person *GamePerson) {
// need to implement
}
}
func WithType(personType int) func(*GamePerson) {
return func(person *GamePerson) {
// need to implement
}
}
const (
BuilderGamePersonType = iota
BlacksmithGamePersonType
WarriorGamePersonType
)
type GamePerson struct {
// need to implement
}
func NewGamePerson(options ...Option) GamePerson {
// need to implement
return GamePerson{}
}
func (p *GamePerson) Name() string {
// need to implement
return ""
}
func (p *GamePerson) X() int {
// need to implement
return 0
}
func (p *GamePerson) Y() int {
// need to implement
return 0
}
func (p *GamePerson) Z() int {
// need to implement
return 0
}
func (p *GamePerson) Gold() int {
// need to implement
return 0
}
func (p *GamePerson) Mana() int {
// need to implement
return 0
}
func (p *GamePerson) Health() int {
// need to implement
return 0
}
func (p *GamePerson) Respect() int {
// need to implement
return 0
}
func (p *GamePerson) Strength() int {
// need to implement
return 0
}
func (p *GamePerson) Experience() int {
// need to implement
return 0
}
func (p *GamePerson) Level() int {
// need to implement
return 0
}
func (p *GamePerson) HasHouse() bool {
// need to implement
return false
}
func (p *GamePerson) HasGun() bool {
// need to implement
return false
}
func (p *GamePerson) HasFamilty() bool {
// need to implement
return false
}
func (p *GamePerson) Type() int {
// need to implement
return 0
}
func TestGamePerson(t *testing.T) {
assert.LessOrEqual(t, unsafe.Sizeof(GamePerson{}), uintptr(64))
const x, y, z = math.MinInt32, math.MaxInt32, 0
const name = "aaaaaaaaaaaaa_bbbbbbbbbbbbb_cccccccccccccc"
const personType = BuilderGamePersonType
const gold = math.MaxInt32
const mana = 1000
const health = 1000
const respect = 10
const strength = 10
const experience = 10
const level = 10
options := []Option{
WithName(name),
WithCoordinates(x, y, z),
WithGold(gold),
WithMana(mana),
WithHealth(health),
WithRespect(respect),
WithStrength(strength),
WithExperience(experience),
WithLevel(level),
WithHouse(),
WithFamily(),
WithType(personType),
}
person := NewGamePerson(options...)
assert.Equal(t, name, person.Name())
assert.Equal(t, x, person.X())
assert.Equal(t, y, person.Y())
assert.Equal(t, z, person.Z())
assert.Equal(t, gold, person.Gold())
assert.Equal(t, mana, person.Mana())
assert.Equal(t, health, person.Health())
assert.Equal(t, respect, person.Respect())
assert.Equal(t, strength, person.Strength())
assert.Equal(t, experience, person.Experience())
assert.Equal(t, level, person.Level())
assert.True(t, person.HasHouse())
assert.True(t, person.HasFamilty())
assert.False(t, person.HasGun())
assert.Equal(t, personType, person.Type())
}

View File

@ -0,0 +1,123 @@
package main
import (
"sync/atomic"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
type RWMutex struct {
// need to implement
}
func (m *RWMutex) Lock() {
// need to implement
}
func (m *RWMutex) Unlock() {
// need to implement
}
func (m *RWMutex) RLock() {
// need to implement
}
func (m *RWMutex) RUnlock() {
// need to implement
}
func TestRWMutexWithWriter(t *testing.T) {
var mutex RWMutex
mutex.Lock() // writer
var mutualExlusionWithWriter atomic.Bool
mutualExlusionWithWriter.Store(true)
var mutualExlusionWithReader atomic.Bool
mutualExlusionWithReader.Store(true)
go func() {
mutex.Lock() // another writer
mutualExlusionWithWriter.Store(false)
}()
go func() {
mutex.RLock() // another reader
mutualExlusionWithReader.Store(false)
}()
time.Sleep(time.Second)
assert.True(t, mutualExlusionWithWriter.Load())
assert.True(t, mutualExlusionWithReader.Load())
}
func TestRWMutexWithReaders(t *testing.T) {
var mutex RWMutex
mutex.RLock() // reader
var mutualExlusionWithWriter atomic.Bool
mutualExlusionWithWriter.Store(true)
go func() {
mutex.Lock() // another writer
mutualExlusionWithWriter.Store(false)
}()
time.Sleep(time.Second)
assert.True(t, mutualExlusionWithWriter.Load())
}
func TestRWMutexMultipleReaders(t *testing.T) {
var mutex RWMutex
mutex.RLock() // reader
var readersCount atomic.Int32
readersCount.Add(1)
go func() {
mutex.RLock() // another reader
readersCount.Add(1)
}()
go func() {
mutex.RLock() // another reader
readersCount.Add(1)
}()
time.Sleep(time.Second)
assert.Equal(t, int32(3), readersCount.Load())
}
func TestRWMutexWithWriterPriority(t *testing.T) {
var mutex RWMutex
mutex.RLock() // reader
var mutualExlusionWithWriter atomic.Bool
mutualExlusionWithWriter.Store(true)
var readersCount atomic.Int32
readersCount.Add(1)
go func() {
mutex.Lock() // another writer is waiting for reader
mutualExlusionWithWriter.Store(false)
}()
time.Sleep(time.Second)
go func() {
mutex.RLock() // another reader is waiting for a higher priority writer
readersCount.Add(1)
}()
go func() {
mutex.RLock() // another reader is waiting for a higher priority writer
readersCount.Add(1)
}()
time.Sleep(time.Second)
assert.True(t, mutualExlusionWithWriter.Load())
assert.Equal(t, int32(1), readersCount.Load())
}

View File

@ -0,0 +1,19 @@
package main
import (
"fmt"
"unsafe"
)
func main() {
var number int32 = 0x12345678
pointer := unsafe.Pointer(&number)
fmt.Printf("0x")
for i := 0; i < 4; i++ {
byteValue := *(*int8)(unsafe.Add(pointer, i))
fmt.Printf("%x", byteValue)
}
fmt.Println()
}

View File

@ -0,0 +1,24 @@
package main
import (
"fmt"
"unsafe"
)
func IsLittleEndian() bool {
var number int16 = 0x0001
pointer := (*int8)(unsafe.Pointer(&number))
return *pointer == 1
}
func IsBigEndian() bool {
return !IsLittleEndian()
}
func main() {
if IsLittleEndian() {
fmt.Println("Little endian")
} else {
fmt.Println("Big endian")
}
}

View File

@ -0,0 +1,20 @@
package main
import (
"fmt"
"math"
)
func main() {
var signed int8 = math.MaxInt8
signed++
var unsigned uint8 = math.MaxUint8
unsigned++
fmt.Println(signed)
fmt.Println(unsigned)
// var signed int8 = math.MaxInt8 + 1 -> compilation error
// var unsigned uint8 = math.MaxUint8 + 1 -> compilation error
}

View File

@ -0,0 +1,11 @@
package main
import "fmt"
func main() {
var x uint8 = 3
var y int8 = 3
fmt.Println(^x)
fmt.Println(^y)
}

View File

@ -0,0 +1,8 @@
package main
import "fmt"
func main() {
sum := 100 + 010
fmt.Println(sum)
}

View File

@ -0,0 +1,52 @@
package main
import (
"errors"
"math"
)
var ErrIntOverflow = errors.New("integer overflow")
func Inc(counter int) (int, error) {
if counter == math.MaxInt {
return 0, ErrIntOverflow
}
return counter + 1, nil
}
func Add(lhs, rhs int) (int, error) {
if rhs > 0 {
if lhs > math.MaxInt-rhs {
return 0, ErrIntOverflow
}
} else if rhs < 0 {
if lhs < math.MinInt-rhs {
return 0, ErrIntOverflow
}
}
return lhs + rhs, nil
}
func Mul(lhs, rhs int) (int, error) {
if lhs == 0 || rhs == 0 {
return 0, nil
}
if lhs == 1 || rhs == 1 {
return lhs * rhs, nil
}
if (lhs == -1 && rhs == math.MinInt) || (rhs == -1 && lhs == math.MinInt) {
return 0, ErrIntOverflow
}
if lhs > math.MaxInt/rhs {
return 0, ErrIntOverflow
} else if lhs < math.MinInt/rhs {
return 0, ErrIntOverflow
}
return lhs * rhs, nil
}

View File

@ -0,0 +1,21 @@
package main
import "fmt"
func process(temp **int32) {
var value2 int32 = 200
*temp = &value2
}
func main() {
var value1 int32 = 100
pointer := &value1
fmt.Println(*pointer)
fmt.Println(pointer)
process(&pointer)
fmt.Println(*pointer)
fmt.Println(pointer)
}

View File

@ -0,0 +1,21 @@
package main
import "fmt"
func process(temp *int32) {
var value2 int32 = 200
temp = &value2
}
func main() {
var value1 int32 = 100
pointer := &value1
fmt.Println(*pointer)
fmt.Println(pointer)
process(pointer)
fmt.Println(*pointer)
fmt.Println(pointer)
}

View File

@ -0,0 +1,29 @@
package main
import (
"runtime"
"unsafe"
)
// go run main.go
// go run -gcflags=-d=checkptr main.go
func main() {
x := new(int)
y := new(int)
z := new(int)
ptrX := unsafe.Pointer(x)
ptrY := unsafe.Pointer(y)
addressZ := uintptr(unsafe.Pointer(z))
// arithmetic operation
_ = addressZ + 2
_ = addressZ - 2
runtime.GC()
*(*int)(ptrX) = 100
*(*int)(ptrY) = 200
*(*int)(unsafe.Pointer(addressZ)) = 300 // dangerous
}

View File

@ -0,0 +1,14 @@
package main
// -l = disable inlining
// -m = print optimization decisions
// go build -gcflags '-l -m'
func getResult() int {
result := 200
return result
}
func main() {
_ = getResult()
}

View File

@ -0,0 +1,14 @@
package main
// -l = disable inlining
// -m = print optimization decisions
// go build -gcflags '-l -m'
func getResult() *int {
result := 200
return &result
}
func main() {
_ = getResult()
}

View File

@ -0,0 +1,15 @@
package main
// -l = disable inlining
// -m = print optimization decisions
// go build -gcflags '-l -m'
func getResult(number *int) int {
result := *number + 200
return result
}
func main() {
number := 100
_ = getResult(&number)
}

View File

@ -0,0 +1,28 @@
package main
import "fmt"
// -l = disable inlining
// -m = print optimization decisions
// go build -gcflags '-l -m'
func printValue(v interface{}) {
fmt.Println(v)
//_, _ = v.(int)
}
func main() {
var num1 int = 10
var str1 string = "Hello"
printValue(num1)
printValue(str1)
var num2 int = 10
var str2 string = "Hello"
var i interface{}
i = num2
i = str2
_ = i
}

View File

@ -0,0 +1,18 @@
package main
// -l = disable inlining
// -m = print optimization decisions
// go build -gcflags '-l -m'
func createPointer() *int {
value2 := new(int)
return value2
}
func main() {
value1 := new(int) // stack
_ = value1
value2 := createPointer() // heap
_ = value2
}

View File

@ -0,0 +1,33 @@
package main
import "testing"
// go test -bench=. -benchmem
type Data struct {
iValue int
sValue string
bValue bool
}
//go:noinline
func NewDataByValue() Data {
return Data{iValue: 100, sValue: "100", bValue: true}
}
//go:noinline
func NewDataByPointer() *Data {
return &Data{iValue: 100, sValue: "100", bValue: true}
}
func BenchmarkNewByValue(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = NewDataByValue()
}
}
func BenchmarkNewByPointer(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = NewDataByPointer()
}
}

View File

@ -0,0 +1,43 @@
package main
import "testing"
// go test -bench=. -benchmem
const bufferSize = 10
type ReaderWithSliceArgument struct{}
func (r ReaderWithSliceArgument) Read(p []byte) (int, error) {
for i := 0; i < bufferSize; i++ {
p[i] = byte(i)
}
return bufferSize, nil
}
type ReaderWithSliceReturn struct{}
func (r ReaderWithSliceReturn) Read(n int) ([]byte, error) {
p := make([]byte, n)
for i := 0; i < n; i++ {
p[i] = byte(i)
}
return p, nil
}
func BenchmarkSliceWithArgument(b *testing.B) {
for i := 0; i < b.N; i++ {
p := make([]byte, bufferSize)
reader := ReaderWithSliceArgument{}
_, _ = reader.Read(p)
}
}
func BenchmarkSliceWithReturn(b *testing.B) {
for i := 0; i < b.N; i++ {
reader := ReaderWithSliceReturn{}
_, _ = reader.Read(bufferSize)
}
}

View File

@ -0,0 +1,28 @@
package main
import "testing"
// go test -bench=. -benchmem
type Data struct {
pointer *int
}
func BenchmarkIteration1(b *testing.B) {
for i := 0; i < b.N; i++ {
var number int
data := &Data{
pointer: &number,
}
_ = data
}
}
func BenchmarkIteration2(b *testing.B) {
for i := 0; i < b.N; i++ {
var number int
data := &Data{}
data.pointer = &number
_ = data
}
}

View File

@ -0,0 +1,26 @@
package main
import (
"fmt"
"unsafe"
)
// For memory blocks larger than 32768 bytes,
// each of them is always composed of multiple
// memory pages. The memory page size used by the
// official standard Go runtime (1.22 versions) is 8192 bytes.
func main() {
var data1 [32769]byte
var data2 [32769]byte
data1Pointer := unsafe.Pointer(&data1)
data2Pointer := unsafe.Pointer(&data2)
fmt.Println("adress:", data1Pointer, data2Pointer)
fmt.Println("size:", unsafe.Sizeof(data1), unsafe.Sizeof(data2))
distance := uintptr(data2Pointer) - uintptr(data1Pointer)
fmt.Println("distance:", distance)
fmt.Println("waste:", distance-unsafe.Sizeof(data1))
}

View File

@ -0,0 +1,24 @@
package main
import (
"fmt"
"testing"
)
var result string
var buffer []byte = make([]byte, 33)
func Concat(b *testing.B) {
for i := 0; i < b.N; i++ {
result = string(buffer) + string(buffer)
}
}
func main() {
b := testing.Benchmark(Concat)
fmt.Println(b.AllocsPerOp()) // 3
fmt.Println(b.AllocedBytesPerOp()) // 176
// alocated 176 bytes = 48 (not 33) + 48 (not 33) + 80 (not 33 + 33 = 66)
// waste = 15 + 15 + 14 = 44 bytes (25% waste)
}

View File

@ -0,0 +1,30 @@
package main
// GOEXPERIMENT=arenas go run main.go
// go run -tags goexperiment.arenas main.go
import (
"arena"
)
type Data struct {
deposit int
credit int
}
func main() {
a := arena.NewArena()
defer a.Free()
value := arena.New[int64](a)
_ = value
data := arena.New[Data](a)
_ = data
slice := arena.MakeSlice[int32](a, 0, 10)
_ = slice
cloned := arena.Clone[*Data](data) // moved to heap
_ = cloned
}

View File

@ -0,0 +1,24 @@
package main
// GOEXPERIMENT=arenas go run main.go
// go run -tags goexperiment.arenas main.go
import (
"arena"
)
type Data struct {
value int
operaions []int
}
func main() {
a := arena.NewArena()
defer a.Free()
// Arenas will not allocate all reference types automatically
operations := arena.MakeSlice[int](a, 0, 100)
data := arena.New[Data](a)
data.operaions = operations
_ = data
}

View File

@ -0,0 +1,18 @@
package main
// GOEXPERIMENT=arenas go run main.go
// go run -tags goexperiment.arenas main.go
import (
"arena"
)
func main() {
mem := arena.NewArena()
defer mem.Free()
slice := arena.NewSlice[int](mem, 0, 5)
slice = append(slice, 1, 2, 3, 4, 5)
slice = append(slice, 6) // moved to heap
}

View File

@ -0,0 +1,23 @@
package main
// GOEXPERIMENT=arenas go run main.go
// go run -tags goexperiment.arenas main.go
import (
"arena"
"fmt"
)
type Data struct {
deposit int
credit int
}
func main() {
a := arena.NewArena()
data := arena.New[Data](a)
a.Free()
// use after free
fmt.Println(data)
}

View File

@ -0,0 +1,22 @@
package main
import "fmt"
// go run main.go
// GOGC=off go run main.go
var data []byte
func main() {
count := 0
for {
data = make([]byte, 1<<30)
/*for idx := 0; idx < 1<<30; idx += 4096 {
data[idx] = 100
}*/
fmt.Println("allocated GB:", count)
count++
}
}

View File

@ -0,0 +1,74 @@
package main
import (
"errors"
"fmt"
"unsafe"
)
type LinearAllocator struct {
data []byte
}
func NewLinearAllocator(capacity int) (LinearAllocator, error) {
if capacity <= 0 {
return LinearAllocator{}, errors.New("incorrect capacity")
}
return LinearAllocator{
data: make([]byte, 0, capacity),
}, nil
}
func (a *LinearAllocator) Allocate(size int) (unsafe.Pointer, error) {
previousLength := len(a.data)
newLength := previousLength + size
if newLength > cap(a.data) {
// can increase capacity
return nil, errors.New("not enough memory")
}
a.data = a.data[:newLength]
pointer := unsafe.Pointer(&a.data[previousLength])
return pointer, nil
}
// not supported by this kind of allocator
// func (a *LinearAllocator) Deallocate(pointer unsafe.Pointer) error {}
func (a *LinearAllocator) Free() {
a.data = a.data[:0]
}
func store[T any](pointer unsafe.Pointer, value T) {
*(*T)(pointer) = value
}
func load[T any](pointer unsafe.Pointer) T {
return *(*T)(pointer)
}
func main() {
const MB = 1 << 20
allocator, err := NewLinearAllocator(MB)
if err != nil {
// handling...
}
defer allocator.Free()
pointer1, _ := allocator.Allocate(2)
pointer2, _ := allocator.Allocate(4)
store[int16](pointer1, 100)
store[int32](pointer2, 200)
value1 := load[int16](pointer1)
value2 := load[int32](pointer2)
fmt.Println("value1:", value1)
fmt.Println("value2:", value2)
fmt.Println("address1:", pointer1)
fmt.Println("address2:", pointer2)
}

View File

@ -0,0 +1,26 @@
package main
// go test -bench=. allocations_test.go -benchmem
import (
"testing"
)
//go:noinline
func Initialize(value *int) {
*value = 1000
}
func BenchmarkWithoutLoopAllocation(b *testing.B) {
var value int
for i := 0; i < b.N; i++ {
Initialize(&value)
}
}
func BenchmarkWithLoopAllocation(b *testing.B) {
for i := 0; i < b.N; i++ {
var value int
Initialize(&value)
}
}

View File

@ -0,0 +1,50 @@
package main
// go test -bench=. pool_test.go -benchmem
import (
"sync"
"testing"
)
type Person struct {
name string
}
type PersonsPool struct {
pool sync.Pool
}
func NewPersonsPool() *PersonsPool {
return &PersonsPool{
pool: sync.Pool{
New: func() interface{} { return new(Person) },
},
}
}
func (p *PersonsPool) Get() *Person {
return p.pool.Get().(*Person)
}
func (p *PersonsPool) Put(person *Person) {
p.pool.Put(person)
}
var gPerson *Person
func BenchmarkWithPool(b *testing.B) {
pool := NewPersonsPool()
for i := 0; i < b.N; i++ {
person := pool.Get()
person.name = "Ivan" // need to reset values
gPerson = person
pool.Put(person)
}
}
func BenchmarkWithoutPool(b *testing.B) {
for i := 0; i < b.N; i++ {
person := &Person{name: "Ivan"}
gPerson = person
}
}

View File

@ -0,0 +1,100 @@
package main
import (
"errors"
"fmt"
"unsafe"
)
type PoolAllocator struct {
objectPool []byte
freeObjects map[unsafe.Pointer]struct{}
objectSize int
}
func NewPoolAllocator(capacity int, objectSize int) (PoolAllocator, error) {
if capacity <= 0 || objectSize <= 0 || capacity%objectSize != 0 {
return PoolAllocator{}, errors.New("incorrect argumnets")
}
allocator := PoolAllocator{
objectPool: make([]byte, capacity),
freeObjects: make(map[unsafe.Pointer]struct{}, capacity/objectSize),
objectSize: objectSize,
}
allocator.resetMemoryState()
return allocator, nil
}
func (a *PoolAllocator) Allocate() (unsafe.Pointer, error) {
if len(a.freeObjects) == 0 {
// can increase capacity
return nil, errors.New("not enough memory")
}
var pointer unsafe.Pointer
for freePointer := range a.freeObjects {
pointer = freePointer
break
}
delete(a.freeObjects, pointer)
return pointer, nil
}
func (a *PoolAllocator) Deallocate(pointer unsafe.Pointer) error {
if pointer == nil {
return errors.New("incorrect pointer")
}
// potentionally incorrect pointer
a.freeObjects[pointer] = struct{}{}
return nil
}
func (a *PoolAllocator) Free() {
a.resetMemoryState()
}
func (a *PoolAllocator) resetMemoryState() {
for offset := 0; offset < len(a.objectPool); offset += a.objectSize {
pointer := unsafe.Pointer(&a.objectPool[offset])
a.freeObjects[pointer] = struct{}{}
}
}
func store[T any](pointer unsafe.Pointer, value T) {
*(*T)(pointer) = value
}
func load[T any](pointer unsafe.Pointer) T {
return *(*T)(pointer)
}
func main() {
const KB = 1 << 10
allocator, err := NewPoolAllocator(KB, 4)
if err != nil {
// handling...
}
defer allocator.Free()
pointer1, _ := allocator.Allocate()
pointer2, _ := allocator.Allocate()
store[int32](pointer1, 100)
store[int32](pointer2, 200)
value1 := load[int32](pointer1)
value2 := load[int32](pointer2)
fmt.Println("value1:", value1)
fmt.Println("value2:", value2)
fmt.Println("address1:", pointer1)
fmt.Println("address2:", pointer2)
allocator.Deallocate(pointer1)
allocator.Deallocate(pointer2)
}

View File

@ -0,0 +1,100 @@
package main
import (
"errors"
"fmt"
"math"
"unsafe"
)
const headerSize = 2
type StackAllocator struct {
data []byte
}
func NewStackAllocator(capacity int) (StackAllocator, error) {
if capacity <= 0 {
return StackAllocator{}, errors.New("incorrect capacity")
}
return StackAllocator{
data: make([]byte, 0, capacity),
}, nil
}
func (a *StackAllocator) Allocate(size int) (unsafe.Pointer, error) {
if size > math.MaxInt16 {
// can increase header size
return nil, errors.New("incorrect size")
}
previousLength := len(a.data)
newLength := previousLength + headerSize + size
if newLength > cap(a.data) {
// can increase capacity
return nil, errors.New("not enough memory")
}
a.data = a.data[:newLength]
header := unsafe.Pointer(&a.data[previousLength])
pointer := unsafe.Pointer(&a.data[previousLength+headerSize])
*(*int16)(header) = int16(size)
return pointer, nil
}
func (a *StackAllocator) Deallocate(pointer unsafe.Pointer) error {
// can deallocate without pointer
if pointer == nil {
return errors.New("incorrect pointer")
}
header := unsafe.Add(pointer, -headerSize)
size := *(*int16)(header)
previousLength := len(a.data)
newLength := previousLength - headerSize - int(size)
a.data = a.data[:newLength]
return nil
}
func (a *StackAllocator) Free() {
a.data = a.data[:0]
}
func store[T any](pointer unsafe.Pointer, value T) {
*(*T)(pointer) = value
}
func load[T any](pointer unsafe.Pointer) T {
return *(*T)(pointer)
}
func main() {
const KB = 1 << 10
allocator, err := NewStackAllocator(KB)
if err != nil {
// handling...
}
defer allocator.Free()
pointer1, _ := allocator.Allocate(2)
defer allocator.Deallocate(pointer1)
pointer2, _ := allocator.Allocate(4)
defer allocator.Deallocate(pointer2)
store[int16](pointer1, 100)
store[int32](pointer2, 200)
value1 := load[int16](pointer1)
value2 := load[int32](pointer2)
fmt.Println("value1:", value1)
fmt.Println("value2:", value2)
fmt.Println("address1:", pointer1)
fmt.Println("address2:", pointer2)
}

View File

@ -0,0 +1,20 @@
package main
// -l = disable inlining
// -m = print optimization decisions
// go build -gcflags '-l -m'
// go run -gcflags '-l' main.go
func process(index int) byte {
var data [1 << 20]byte
return data[index]
}
func main() {
var index int = 100
pointer := &index
println("pointer:", pointer)
process(index)
println("pointer:", pointer)
}

View File

@ -0,0 +1,38 @@
package main
import (
"fmt"
"sync"
)
func notifier(signals chan int) {
close(signals)
}
func subscriber(signals chan int) {
<-signals
fmt.Println("signaled")
}
func main() {
signals := make(chan int)
wg := sync.WaitGroup{}
wg.Add(3)
go func() {
defer wg.Done()
notifier(signals)
}()
go func() {
defer wg.Done()
subscriber(signals)
}()
go func() {
defer wg.Done()
subscriber(signals)
}()
wg.Wait()
}

View File

@ -0,0 +1,7 @@
package main
func main() {
ch := make(chan int, 2)
ch <- 100
ch <- 100
}

View File

@ -0,0 +1,21 @@
package main
import "sync"
// go run -race main.go
var buffer chan int
func main() {
wg := sync.WaitGroup{}
wg.Add(100)
for i := 0; i < 100; i++ {
go func() {
defer wg.Done()
buffer = make(chan int)
}()
}
wg.Wait()
}

View File

@ -0,0 +1,21 @@
package main
import (
"fmt"
"time"
)
// Describe blocking
func async(ch chan string) {
time.Sleep(2 * time.Second)
ch <- "async result"
}
func main() {
ch := make(chan string)
go async(ch)
// ...
result := <-ch
fmt.Println(result)
}

View File

@ -0,0 +1,14 @@
package main
import "fmt"
func main() {
source := make(chan int)
clone := source
go func() {
source <- 1
}()
fmt.Println(<-clone)
}

View File

@ -0,0 +1,46 @@
package main
import (
"sync"
)
var actions int
var mutex sync.Mutex
var buffer chan struct{}
func consumer() {
for i := 0; i < 1000; i++ {
mutex.Lock()
actions++
<-buffer
mutex.Unlock()
}
}
func producer() {
for i := 0; i < 1000; i++ {
buffer <- struct{}{}
mutex.Lock()
actions++
mutex.Unlock()
}
}
func main() {
wg := sync.WaitGroup{}
wg.Add(2)
buffer = make(chan struct{}, 1)
go func() {
defer wg.Done()
consumer()
}()
go func() {
defer wg.Done()
producer()
}()
wg.Wait()
}

View File

@ -0,0 +1,26 @@
package main
import (
"fmt"
"log"
"time"
)
func main() {
doWork := func(strings <-chan string) {
go func() {
for str := range strings {
fmt.Println(str)
}
log.Println("doWork exited")
}()
}
strings := make(chan string)
doWork(strings)
strings <- "Test"
time.Sleep(time.Second)
fmt.Println("Done")
}

View File

@ -0,0 +1,15 @@
package main
// Need to show solution and describe close
// First-response-wins strategy
func request() int {
ch := make(chan int)
for i := 0; i < 5; i++ {
go func() {
ch <- i // 4 goroutines will be blocked
}()
}
return <-ch
}

View File

@ -0,0 +1,22 @@
package main
import (
"fmt"
)
func main() {
ch := make(chan int)
go func() {
ch <- 1
}()
go func() {
ch <- 1
}()
value := 0
value += <-ch
value += <-ch
fmt.Println(value)
}

View File

@ -0,0 +1,27 @@
package main
import (
"fmt"
"sync"
)
func main() {
mutex := sync.Mutex{}
wg := sync.WaitGroup{}
wg.Add(2)
value := 0
for i := 0; i < 2; i++ {
go func() {
defer wg.Done()
mutex.Lock()
value++
mutex.Unlock()
}()
}
wg.Wait()
fmt.Println(value)
}

View File

@ -0,0 +1,19 @@
package main
import "fmt"
func IsClosed(ch chan int) bool {
select {
case <-ch:
return true
default:
return false
}
}
func main() {
ch := make(chan int)
fmt.Println(IsClosed(ch))
close(ch)
fmt.Println(IsClosed(ch))
}

View File

@ -0,0 +1,22 @@
package main
import "fmt"
// Need to show solution
func IsClosed(ch chan int) bool {
select {
case <-ch:
return true
default:
return false
}
}
func main() {
ch := make(chan int, 1)
ch <- 1
fmt.Println(IsClosed(ch))
close(ch)
fmt.Println(IsClosed(ch))
}

View File

@ -0,0 +1,47 @@
package main
import (
"fmt"
"sync"
)
// Need to show solution
func WaitToClose(lhs, rhs chan struct{}) {
lhsClosed, rhsClosed := false, false
for !lhsClosed || !rhsClosed {
select {
case _, ok := <-lhs:
fmt.Println("lhs", ok)
if !ok {
lhsClosed = true
}
case _, ok := <-rhs:
fmt.Println("rhs", ok)
if !ok {
rhsClosed = true
}
}
}
}
func main() {
lhs := make(chan struct{}, 1)
rhs := make(chan struct{}, 1)
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
defer wg.Done()
WaitToClose(lhs, rhs)
}()
lhs <- struct{}{}
rhs <- struct{}{}
close(lhs)
close(rhs)
wg.Wait()
}

View File

@ -0,0 +1,19 @@
package main
import "fmt"
func main() {
ch := make(chan int, 1)
for done := false; !done; {
select {
default:
fmt.Println(3)
done = true
case <-ch:
fmt.Println(2)
ch = nil
case ch <- 1:
fmt.Println(1)
}
}
}

View File

@ -0,0 +1,27 @@
package main
func tryToReadFromChannel(ch chan string) (string, bool) {
select {
case value := <-ch:
return value, true
default:
return "", false
}
}
func tryToWriteToChannel(ch chan string, value string) bool {
select {
case ch <- value:
return true
default:
return false
}
}
func tryToReadOrWrite(ch1 chan string, ch2 chan string) {
select {
case <-ch1:
case ch2 <- "test":
default:
}
}

View File

@ -0,0 +1,19 @@
package main
func tryToReadFromChannel(ch chan string) (string, bool) {
if len(ch) != 0 {
value := <-ch
return value, true
} else {
return "", false
}
}
func tryToWriteToChannel(ch chan string, value string) bool {
if len(ch) < cap(ch) {
ch <- value
return true
} else {
return false
}
}

View File

@ -0,0 +1,91 @@
package main
import (
"fmt"
)
func writeToNilChannel() {
var ch chan int
ch <- 1
}
func writeToClosedChannel() {
ch := make(chan int, 2)
close(ch)
ch <- 20
}
// Descibe read after close
func readFromChannel() {
ch := make(chan int, 2)
ch <- 10
ch <- 20
val, ok := <-ch
fmt.Println(val, ok)
close(ch)
val, ok = <-ch
fmt.Println(val, ok)
val, ok = <-ch
fmt.Println(val, ok)
}
func readAnyChannels() {
ch1 := make(chan int)
ch2 := make(chan int)
go func() {
ch1 <- 100
}()
go func() {
ch2 <- 200
}()
select {
case val1 := <-ch1:
fmt.Println(val1)
case val2 := <-ch2:
fmt.Println(val2)
}
}
func readFromNilChannel() {
var ch chan int
<-ch
}
func rangeNilChannel() {
var ch chan int
for range ch {
}
}
func closeNilChannel() {
var ch chan int
close(ch)
}
func closeChannelAnyTimes() {
ch := make(chan int)
close(ch)
close(ch)
}
func compareChannels() {
ch1 := make(chan int)
ch2 := make(chan int)
equal1 := ch1 == ch2
equal2 := ch1 == ch1
fmt.Println(equal1)
fmt.Println(equal2)
}
func main() {
}

View File

@ -0,0 +1,33 @@
package main
import (
"fmt"
"time"
)
// Need to show solution
func producer(ch chan<- int) {
for {
ch <- 1
time.Sleep(time.Second)
}
}
func main() {
ch1 := make(chan int) // more prioritized
ch2 := make(chan int)
go producer(ch1)
go producer(ch2)
for {
select {
case value := <-ch1:
fmt.Println(value)
return
case value := <-ch2:
fmt.Println(value)
}
}
}

View File

@ -0,0 +1,27 @@
package main
import "fmt"
func main() {
ch1 := make(chan struct{}, 1)
ch2 := make(chan struct{}, 1)
close(ch1)
close(ch2)
ch1Value := 0.0
ch2Value := 0.0
for i := 0; i < 100000; i++ {
select {
case <-ch1:
ch1Value++
case <-ch1:
ch1Value++
case <-ch2:
ch2Value++
}
}
fmt.Println(ch1Value / ch2Value)
}

View File

@ -0,0 +1,51 @@
package main
import (
"fmt"
"sync"
)
func producer(ch chan int) {
defer close(ch)
for i := 0; i < 5; i++ {
ch <- i
}
}
func consumer(ch chan int) {
/*
for {
select {
case value, opened := <-ch:
if !opened {
return
}
fmt.Println(value)
}
}
*/
for value := range ch { // syntax sugar
fmt.Println(value)
}
}
func main() {
ch := make(chan int)
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
defer wg.Done()
producer(ch)
}()
go func() {
defer wg.Done()
consumer(ch)
}()
wg.Wait()
}

View File

@ -0,0 +1,36 @@
package main
import (
"fmt"
"time"
)
func async1() chan string {
ch := make(chan string)
go func() {
time.Sleep(1 * time.Second)
ch <- "async1 result"
}()
return ch
}
func async2() chan string {
ch := make(chan string)
go func() {
time.Sleep(1 * time.Second)
ch <- "async2 result"
}()
return ch
}
func main() {
ch1 := async1()
ch2 := async2()
select {
case result := <-ch1:
fmt.Println(result)
case result := <-ch2:
fmt.Println(result)
}
}

View File

@ -0,0 +1,29 @@
package main
func way1() {
make(chan struct{}) <- struct{}{}
// or
make(chan<- struct{}) <- struct{}{}
}
func way2() {
<-make(chan struct{})
// or
<-make(<-chan struct{})
// or
for range make(<-chan struct{}) {
}
}
func way3() {
chan struct{}(nil) <- struct{}{}
// or
<-chan struct{}(nil)
// or
for range chan struct{}(nil) {
}
}
func way4() {
select {}
}

View File

@ -0,0 +1,33 @@
package main
import "fmt"
func main() {
data := make(chan int)
go func() {
for i := 1; i <= 4; i++ {
data <- i
}
close(data)
}()
for {
value := 0
opened := true
select {
case value, opened = <-data:
if value == 2 {
continue
} else if value == 3 {
break
}
if !opened {
return
}
}
fmt.Println(value)
}
}

View File

@ -0,0 +1,15 @@
package main
import "runtime"
func doSomething() {
for {
runtime.Gosched()
}
}
func main() {
go doSomething()
go doSomething()
select {}
}

View File

@ -0,0 +1,38 @@
package main
import (
"fmt"
"time"
)
// Need to show solution
func FetchData1() chan int {
ch := make(chan int)
go func() {
time.Sleep(time.Second * 2)
ch <- 10
}()
return ch
}
func FetchData2() chan int {
ch := make(chan int)
go func() {
time.Sleep(time.Second * 2)
ch <- 20
}()
return ch
}
func Process(value1, value2 int) {
// Processing...
}
func main() {
start := time.Now()
Process(<-FetchData1(), <-FetchData2())
fmt.Println(time.Now().Sub(start))
}

View File

@ -0,0 +1,33 @@
package main
import (
"fmt"
"sync"
)
func notifier(signals chan struct{}) {
signals <- struct{}{}
}
func subscriber(signals chan struct{}) {
<-signals
fmt.Println("signaled")
}
func main() {
signals := make(chan struct{})
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
defer wg.Done()
notifier(signals)
}()
go func() {
defer wg.Done()
subscriber(signals)
}()
wg.Wait()
}

View File

@ -0,0 +1,19 @@
package main
import "fmt"
func in(in chan<- int) {
in <- 100
close(in)
}
func out(out <-chan int) {
fmt.Println(<-out)
}
func main() {
var ch = make(chan int, 1)
in(ch)
out(ch)
}

View File

@ -0,0 +1,19 @@
package main
import (
"time"
)
func main() {
ch := make(chan int)
go func() {
ch <- 1
}()
time.Sleep(500 * time.Millisecond)
close(ch)
<-ch
time.Sleep(100 * time.Millisecond)
}

View File

@ -0,0 +1,29 @@
package main
import (
"context"
"fmt"
"time"
)
// context.AfterFunc
func WithCtxAfterFunc(ctx context.Context, action func()) {
if action != nil {
go func() {
<-ctx.Done()
action()
}()
}
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
WithCtxAfterFunc(ctx, func() {
fmt.Println("after")
})
cancel()
time.Sleep(100 * time.Millisecond)
}

View File

@ -0,0 +1,17 @@
package main
import "context"
func incorrectCheck(ctx context.Context, stream <-chan string) {
data := <-stream
_ = data
}
func correctCheck(ctx context.Context, stream <-chan string) {
select {
case data := <-stream:
_ = data
case <-ctx.Done():
return
}
}

View File

@ -0,0 +1,26 @@
package main
import (
"context"
"time"
)
func Query(string) string
func DoQeury(qyeryStr string) (string, error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
defer cancel()
var resultCh chan string
go func() {
result := Query(qyeryStr)
resultCh <- result
}()
select {
case <-ctx.Done():
return "", ctx.Err()
case result := <-resultCh:
return result, nil
}
}

View File

@ -0,0 +1,29 @@
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
makeRequest(ctx)
}
func makeRequest(ctx context.Context) {
timer := time.NewTimer(5 * time.Second)
defer timer.Stop()
newCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
select {
case <-newCtx.Done():
fmt.Println("canceled")
case <-timer.C:
fmt.Println("timer")
}
}

View File

@ -0,0 +1,19 @@
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_, cancel = context.WithCancel(ctx)
cancel()
if ctx.Err() != nil {
fmt.Println("canceled")
}
}

View File

@ -0,0 +1,44 @@
package main
import (
"context"
"fmt"
"math/rand"
"sync"
"time"
)
func receiveWeather(ctx context.Context, result chan struct{}, idx int) {
randomTime := time.Duration(rand.Intn(5000)) * time.Millisecond
timer := time.NewTimer(randomTime)
defer timer.Stop()
select {
case <-timer.C:
fmt.Printf("finished: %d\n", idx)
result <- struct{}{}
case <-ctx.Done():
fmt.Printf("canceled: %d\n", idx)
}
}
func main() {
wg := sync.WaitGroup{}
wg.Add(10)
ctx, cancel := context.WithCancel(context.Background())
result := make(chan struct{}, 10)
for i := 0; i < 10; i++ {
go func(idx int) {
defer wg.Done()
receiveWeather(ctx, result, idx)
}(i)
}
<-result
cancel()
wg.Wait()
}

View File

@ -0,0 +1,15 @@
package main
import (
"context"
"errors"
"fmt"
)
func main() {
ctx, cancel := context.WithCancelCause(context.Background())
cancel(errors.New("error"))
fmt.Println(ctx.Err())
fmt.Println(context.Cause(ctx))
}

View File

@ -0,0 +1,22 @@
package main
import (
"context"
"fmt"
"net/http"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://example.com", nil)
if err != nil {
fmt.Println(err.Error())
}
if _, err = http.DefaultClient.Do(req); err != nil {
fmt.Println(err.Error())
}
}

View File

@ -0,0 +1,34 @@
package main
import (
"context"
"fmt"
"net/http"
)
func main() {
helloWorldHandler := http.HandlerFunc(handle)
http.Handle("/welcome", injectTraceID(helloWorldHandler))
_ = http.ListenAndServe(":8080", nil)
}
func handle(_ http.ResponseWriter, r *http.Request) {
value, ok := r.Context().Value("trace_id").(string)
if ok {
fmt.Println(value)
}
makeRequest(r.Context())
}
func makeRequest(_ context.Context) {
// requesting to database with context
}
func injectTraceID(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := context.WithValue(r.Context(), "trace_id", "12-21-33")
req := r.WithContext(ctx)
next.ServeHTTP(w, req)
})
}

View File

@ -0,0 +1,26 @@
package main
import (
"context"
"fmt"
"time"
)
func makeRequest(ctx context.Context) {
timer := time.NewTimer(5 * time.Second)
defer timer.Stop()
select {
case <-timer.C:
fmt.Println("finished")
case <-ctx.Done():
fmt.Println("canceled")
}
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
makeRequest(ctx)
}

View File

@ -0,0 +1,18 @@
package main
import (
"context"
"errors"
"fmt"
"time"
)
func main() {
ctx, cancel := context.WithTimeoutCause(context.Background(), time.Second, errors.New("timeout"))
defer cancel() // show difference
<-ctx.Done()
fmt.Println(ctx.Err())
fmt.Println(context.Cause(ctx))
}

View File

@ -0,0 +1,81 @@
package main
import (
"errors"
"fmt"
"sync/atomic"
"time"
)
type Context struct {
done chan struct{}
closed int32
}
func WithTimeout(parent Context, duration time.Duration) (*Context, func()) {
if atomic.LoadInt32(&parent.closed) == 1 {
return nil, nil // don't use nil
}
ctx := &Context{
done: make(chan struct{}),
}
cancel := func() {
if atomic.CompareAndSwapInt32(&ctx.closed, 0, 1) {
close(ctx.done)
}
}
go func() {
timer := time.NewTimer(duration)
defer timer.Stop()
select {
case <-parent.Done():
case <-timer.C:
}
cancel()
}()
return ctx, cancel
}
func (c *Context) Done() <-chan struct{} {
return c.done
}
func (c *Context) Err() error {
select {
case <-c.done:
return errors.New("context deadline exceeded")
default:
return nil
}
}
func (c *Context) Deadline() (time.Time, bool) {
// not implemented
return time.Time{}, false
}
func (c *Context) Value(any) any {
// not implemented
return nil
}
func main() {
ctx, cancel := WithTimeout(Context{}, time.Second)
defer cancel()
timer := time.NewTimer(5 * time.Second)
defer timer.Stop()
select {
case <-timer.C:
fmt.Println("finished")
case <-ctx.Done():
fmt.Println("canceled")
}
}

View File

@ -0,0 +1,29 @@
package main
import (
"context"
"fmt"
)
func main() {
traceCtx := context.WithValue(context.Background(), "trace_id", "12-21-33")
makeRequest(traceCtx)
oldValue, ok := traceCtx.Value("trace_id").(string)
if ok {
fmt.Println("mainValue", oldValue)
}
}
func makeRequest(ctx context.Context) {
oldValue, ok := ctx.Value("trace_id").(string)
if ok {
fmt.Println("oldValue", oldValue)
}
newCtx := context.WithValue(ctx, "trace_id", "22-22-22")
newValue, ok := newCtx.Value("trace_id").(string)
if ok {
fmt.Println("newValue", newValue)
}
}

View File

@ -0,0 +1,26 @@
package main
import (
"context"
"fmt"
)
func main() {
traceCtx := context.WithValue(context.Background(), "trace_id", "12-21-33")
makeRequest(traceCtx)
}
func makeRequest(ctx context.Context) {
oldValue, ok := ctx.Value("trace_id").(string)
if ok {
fmt.Println(oldValue)
}
newCtx, cancel := context.WithCancel(ctx)
defer cancel()
newValue, ok := newCtx.Value("trace_id").(string)
if ok {
fmt.Println(newValue)
}
}

View File

@ -0,0 +1,27 @@
package main
import (
"context"
"fmt"
)
func main() {
{
ctx := context.WithValue(context.Background(), "key", "value1")
ctx = context.WithValue(ctx, "key", "value2")
fmt.Println("string =", ctx.Value("key").(string))
}
{
type key1 string // type definition, not type alias
type key2 string // type definition, not type alias
const k1 key1 = "key"
const k2 key2 = "key"
ctx := context.WithValue(context.Background(), k1, "value1")
ctx = context.WithValue(ctx, k2, "value2")
fmt.Println("key1 =", ctx.Value(k1).(string))
fmt.Println("key2 =", ctx.Value(k2).(string))
}
}

View File

@ -0,0 +1,17 @@
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
innerCtx := context.WithoutCancel(ctx)
cancel()
if innerCtx.Err() != nil {
fmt.Println("canceled")
}
}

View File

@ -0,0 +1,5 @@
module errgroup
go 1.20
require golang.org/x/sync v0.6.0

View File

@ -0,0 +1,2 @@
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=

View File

@ -0,0 +1,39 @@
package main
import (
"context"
"errors"
"fmt"
"math/rand"
"time"
"golang.org/x/sync/errgroup"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
group, groupCtx := errgroup.WithContext(ctx)
for i := 0; i < 10; i++ {
group.Go(func() error {
timeout := time.Second * time.Duration(rand.Intn(10))
timer := time.NewTimer(timeout)
defer timer.Stop()
select {
case <-timer.C:
fmt.Println("timeout")
return errors.New("error")
case <-groupCtx.Done():
fmt.Println("canceled")
return nil
}
})
}
if err := group.Wait(); err != nil {
fmt.Println(err.Error())
}
}

View File

@ -0,0 +1,43 @@
package main
import (
"context"
"fmt"
"io"
"log"
"net/http"
"os"
"os/signal"
"time"
)
func main() {
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop()
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
_, _ = io.WriteString(w, "hello world\n")
})
server := &http.Server{
Addr: ":8888",
}
go func() {
err := server.ListenAndServe()
if err != nil && err != http.ErrServerClosed {
log.Print(err.Error()) // exit
}
}()
<-ctx.Done()
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
cancel()
if err := server.Shutdown(ctx); err != nil {
log.Print(err.Error())
}
fmt.Println("canceled")
}

View File

@ -0,0 +1,15 @@
package main
import (
"context"
)
func process(ctx context.Context) {
if ctx.Err() != nil {
// handling...
}
}
func main() {
process(nil)
}

View File

@ -0,0 +1,18 @@
package main
import "context"
func WithContexCheck(ctx context.Context, action func()) {
if action == nil || ctx.Err() != nil {
return
}
action()
}
func main() {
ctx := context.Background()
WithContexCheck(ctx, func() {
// do something
})
}

View File

@ -0,0 +1,36 @@
package main
import "fmt"
const (
OpenModeIn = 1 // 0000 0001
OpenModeOut = 2 // 0000 0010
OpenModeAppend = 4 // 0000 0100
OpenModeBinary = 8 // 0000 1000
// sugar for prepared masks
OpenModeInAndOut = OpenModeIn | OpenModeOut // 0000 0001 + 0000 0010 = 0000 0011
)
func Open(filename string, mask int8) {
if mask&OpenModeIn != 0 {
fmt.Println("in mode")
}
if mask&OpenModeOut != 0 {
fmt.Println("out mode")
}
if mask&OpenModeAppend != 0 {
fmt.Println("append mode")
}
if mask&OpenModeBinary != 0 {
fmt.Println("binary mode")
}
// implementation...
}
func main() {
Open("data.bin", OpenModeIn|OpenModeBinary) // 0000 1001
Open("data.bin", OpenModeIn|OpenModeOut) // 0000 0011
Open("data.bin", OpenModeAppend) // 0000 0100
}

View File

@ -0,0 +1,17 @@
package main
func IsSetBit(number, index int) bool {
return (number & (1 << index)) != 0
}
func SetBit(number, index int) int {
return number | (1 << index)
}
func InverseBit(number, index int) int {
return number ^ (1 << index)
}
func ResetBit(number, index int) int {
return number & ^(1 << index)
}

Some files were not shown because too many files have changed in this diff Show More