diff --git a/part_10/10.1/udp/client/client.go b/part_10/10.1/udp/client/client.go new file mode 100644 index 0000000..16a4838 --- /dev/null +++ b/part_10/10.1/udp/client/client.go @@ -0,0 +1,46 @@ +package client + +import ( + "fmt" + "log" + "net" +) + +func checkErr(err error) { + if err != nil { + log.Fatal(err) + } +} + +func RunClient(port int) { + s, _ := net.ResolveUDPAddr("udp4", fmt.Sprintf("localhost:%d", port)) + connection, err := net.DialUDP("udp4", nil, s) + checkErr(err) + + fmt.Printf("The UDP server is %s\n", connection.RemoteAddr().String()) + defer connection.Close() + count := 0 + for { + data := []byte(fmt.Sprintf("%d)Hello!\n", count)) + fmt.Print("->", string(data)) + _, err = connection.Write(data) + + checkErr(err) + + buffer := make([]byte, 1024) + n, _, err := connection.ReadFromUDP(buffer) + checkErr(err) + + fmt.Printf("<-: %s", string(buffer[0:n])) + count++ + if count >= 5 { + data := []byte("STOP") + fmt.Println("->", string(data)) + _, err = connection.Write(data) + checkErr(err) + + fmt.Println("Finished!") + return + } + } +} diff --git a/part_10/10.1/udp/go.mod b/part_10/10.1/udp/go.mod new file mode 100644 index 0000000..c224feb --- /dev/null +++ b/part_10/10.1/udp/go.mod @@ -0,0 +1,3 @@ +module udp + +go 1.24 diff --git a/part_10/10.1/udp/main.go b/part_10/10.1/udp/main.go new file mode 100644 index 0000000..76f68b4 --- /dev/null +++ b/part_10/10.1/udp/main.go @@ -0,0 +1,38 @@ +package main + +import ( + "fmt" + "log" + "os" + "strconv" + "udp/client" + "udp/server" +) + +const PORT = 8081 + +func checkErr(err error) { + if err != nil { + log.Fatal(err) + } +} + +func main() { + if len(os.Args) != 2 { + fmt.Println("You didn't select a launch option!!!") + return + } + numGR, err := strconv.Atoi(os.Args[1]) + checkErr(err) + + switch numGR { + case 1: + fmt.Println("Server is running") + server.RunServer(PORT) + case 2: + fmt.Println("Client is running") + client.RunClient(PORT) + default: + log.Fatal("What pokemon is this?") + } +} diff --git a/part_10/10.1/udp/server/server.go b/part_10/10.1/udp/server/server.go new file mode 100644 index 0000000..09eef1e --- /dev/null +++ b/part_10/10.1/udp/server/server.go @@ -0,0 +1,44 @@ +package server + +import ( + "fmt" + "log" + "net" + "strings" + "time" +) + +func checkErr(err error) { + if err != nil { + log.Fatal(err) + } +} + +func RunServer(port int) { + s, err := net.ResolveUDPAddr("udp4", fmt.Sprintf(":%d", port)) + checkErr(err) + + connection, err := net.ListenUDP("udp4", s) + checkErr(err) + + defer connection.Close() + buffer := make([]byte, 1024) + fmt.Println("Oo") + for { + n, addr, err := connection.ReadFromUDP(buffer) // ждем подсоединение клиента + checkErr(err) + fmt.Printf("<- %s", string(buffer[0:n])) + + if strings.TrimSpace(string(buffer[0:n])) == "STOP" { + fmt.Println() + fmt.Println("Exiting UDP server!") + return + } + + time.Sleep(5 * time.Second) + + fmt.Printf("->: %s", string(buffer)) + _, err = connection.WriteToUDP(buffer, addr) + checkErr(err) + } +} diff --git a/part_10/10.2/tcp/client/client.go b/part_10/10.2/tcp/client/client.go new file mode 100644 index 0000000..9261a66 --- /dev/null +++ b/part_10/10.2/tcp/client/client.go @@ -0,0 +1,53 @@ +package client + +import ( + "bufio" + "fmt" + "log" + "net" +) + +func checkErr(err error) { + if err != nil { + log.Fatal(err) + } +} + +func RunClient(port int) { + // запускает реализацию клиента TCP и соединяет вас с нужным TCP-сервером + connection, err := net.Dial("tcp", fmt.Sprintf("localhost:%d", port)) + checkErr(err) + + fmt.Printf("The TCP server is %s\n", connection.RemoteAddr().String()) + defer connection.Close() + count := 0 + for { + // отправка сообщения на сервер + data := []byte(fmt.Sprintf("%d)Hello!\n", count)) + fmt.Print("->", string(data)) + fmt.Fprint(connection, fmt.Sprintf("%d)Hello!\n", count)) + // или + //_, err = connection.Write(data) + // checkErr(err) + + // считываем ответ TCP-сервера + message, err := bufio.NewReader(connection).ReadString('\n') + // или + // buffer := make([]byte, 1024) + // _, err := connection.Read(buffer) + // message := string(buffer) + checkErr(err) + + fmt.Printf("<-: %s", message) + count++ + if count >= 5 { + data := []byte("STOP") + fmt.Println("->", string(data)) + _, err = connection.Write(data) + checkErr(err) + + fmt.Println("Finished!") + return + } + } +} diff --git a/part_10/10.2/tcp/go.mod b/part_10/10.2/tcp/go.mod new file mode 100644 index 0000000..540e7dc --- /dev/null +++ b/part_10/10.2/tcp/go.mod @@ -0,0 +1,3 @@ +module udp/server + +go 1.24 diff --git a/part_10/10.2/tcp/main.go b/part_10/10.2/tcp/main.go new file mode 100644 index 0000000..8f40b03 --- /dev/null +++ b/part_10/10.2/tcp/main.go @@ -0,0 +1,38 @@ +package main + +import ( + "fmt" + "log" + "os" + "strconv" + "udp/server/client" + "udp/server/server" +) + +const PORT = 8081 + +func checkErr(err error) { + if err != nil { + log.Fatal(err) + } +} + +func main() { + if len(os.Args) != 2 { + fmt.Println("You didn't select a launch option!!!") + return + } + numGR, err := strconv.Atoi(os.Args[1]) + checkErr(err) + + switch numGR { + case 1: + fmt.Println("Server is running") + server.RunServer(PORT) + case 2: + fmt.Println("Client is running") + client.RunClient(PORT) + default: + log.Fatal("What pokemon is this?") + } +} diff --git a/part_10/10.2/tcp/server/server.go b/part_10/10.2/tcp/server/server.go new file mode 100644 index 0000000..ecf2c84 --- /dev/null +++ b/part_10/10.2/tcp/server/server.go @@ -0,0 +1,62 @@ +package server + +import ( + "fmt" + "log" + "net" + "strings" + "time" +) + +func checkErr(err error) { + if err != nil { + log.Print(err) + } +} + +func handleConnection(connection net.Conn) { + defer connection.Close() + + buffer := make([]byte, 1024) + for { + n, err := connection.Read(buffer) // считывание данных + checkErr(err) + fmt.Printf("Receive: %s from %s\n", + string(buffer[0:n-1]), connection.RemoteAddr().String()) + + if strings.TrimSpace(string(buffer[0:n])) == "STOP" { + // завершение работы сервера + fmt.Println() + fmt.Printf("Close connection with client: %s\n", + connection.RemoteAddr().String()) + break + } + + time.Sleep(2 * time.Second) + + fmt.Printf("Send : %s to %s\n", + string(buffer[0:n-1]), connection.RemoteAddr().String()) + _, err = connection.Write(buffer) // отправка сообщения клиенту + checkErr(err) + } +} + +func RunServer(port int) { + // net.Listen возвращает Listener переменную, + // которая является общим сетевым прослушивателем для потоковых протоколов + listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) + checkErr(err) + + defer listener.Close() + + for { + connection, err := listener.Accept() // ожидание подключения клиента к серверу + // Только после успешного вызова Accept()TCP-сервер может начать + // взаимодействовать с TCP-клиентами + if err != nil { + log.Print(err) + return + } + go handleConnection(connection) + } +} diff --git a/part_10/10.3/tcp-chat/client/client.go b/part_10/10.3/tcp-chat/client/client.go new file mode 100644 index 0000000..43089cb --- /dev/null +++ b/part_10/10.3/tcp-chat/client/client.go @@ -0,0 +1,77 @@ +package client + +import ( + "bufio" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "sync" +) + +var waitingGr sync.WaitGroup + +func checkErr(err error) { + if err != nil { + log.Fatal(err) + } +} + +func sendMessage(connection net.Conn, waitingGr *sync.WaitGroup) { + defer waitingGr.Done() + for { + reader := bufio.NewReader(os.Stdin) // считываем введенное сообщение + text, _ := reader.ReadString('\n') + + if strings.TrimSuffix(strings.TrimSpace(text), "\r\n") == "/stop" { + // завершение работы клиента + break + } else { + _, err := connection.Write([]byte(text)) + checkErr(err) + } + } +} + +func receiveMessage(connection net.Conn, waitingGr *sync.WaitGroup) { + defer waitingGr.Done() + for { + // ждем сообщение от сервера и считываем его + message, err := bufio.NewReader(connection).ReadString('\n') + + if err == io.EOF { + fmt.Println("Connection close!") + break + } else if err != nil { + fmt.Println(err.Error()) + break + } + + message = message[:len(message)-1] // обрезаем символ перевода на следующую строку + fmt.Println(string(message)) + } +} + +func RunClient(port int) { + // запускает реализацию клиента TCP и соединяет вас с нужным TCP-сервером + connection, err := net.Dial("tcp", fmt.Sprintf("localhost:%d", port)) + checkErr(err) + + fmt.Printf("The TCP server is %s\n", connection.RemoteAddr().String()) + defer connection.Close() + + waitingGr.Add(1) + + fmt.Println("Enter name: ") + temp := bufio.NewReader(os.Stdin) + userName, _ := temp.ReadString('\n') + _, err = connection.Write([]byte(userName)) + checkErr(err) + + go sendMessage(connection, &waitingGr) + go receiveMessage(connection, &waitingGr) + + waitingGr.Wait() +} diff --git a/part_10/10.3/tcp-chat/go.mod b/part_10/10.3/tcp-chat/go.mod new file mode 100644 index 0000000..aecef7d --- /dev/null +++ b/part_10/10.3/tcp-chat/go.mod @@ -0,0 +1,3 @@ +module tcp/server + +go 1.24 diff --git a/part_10/10.3/tcp-chat/main.go b/part_10/10.3/tcp-chat/main.go new file mode 100644 index 0000000..cbfe962 --- /dev/null +++ b/part_10/10.3/tcp-chat/main.go @@ -0,0 +1,38 @@ +package main + +import ( + "fmt" + "log" + "os" + "strconv" + "tcp/server/client" + "tcp/server/server" +) + +const PORT = 8081 + +func checkErr(err error) { + if err != nil { + log.Fatal(err) + } +} + +func main() { + if len(os.Args) != 2 { + fmt.Println("You didn't select a launch option!!!") + return + } + numGR, err := strconv.Atoi(os.Args[1]) + checkErr(err) + + switch numGR { + case 1: + fmt.Println("Server is running") + server.RunServer(PORT) + case 2: + fmt.Println("Client is running") + client.RunClient(PORT) + default: + log.Fatal("What pokemon is this?") + } +} diff --git a/part_10/10.3/tcp-chat/server/server.go b/part_10/10.3/tcp-chat/server/server.go new file mode 100644 index 0000000..9116898 --- /dev/null +++ b/part_10/10.3/tcp-chat/server/server.go @@ -0,0 +1,85 @@ +package server + +import ( + "bufio" + "fmt" + "log" + "net" +) + +var connections []net.Conn + +func checkErr(err error) { + if err != nil { + log.Print(err) + } +} + +func handleConnection(connection net.Conn) { + connections = append(connections, connection) + userName, _ := bufio.NewReader(connection).ReadString('\n') + userName = userName[:len(userName)-2] + _, err := connection.Write([]byte("Hi " + userName + "\n")) + checkErr(err) + + for { + text, err := bufio.NewReader(connection).ReadString('\n') + if err != nil { + connection.Close() + removeConnection(connection) + broadCastMessage(userName+" is offline\n", connection) + break + } + + broadCastMessage(userName+":"+text, connection) + } +} + +func removeConnection(connection net.Conn) { + var i int + + for i = range connections { + if connections[i] == connection { + break + } + } + + if len(connections) > 1 { + connections = append(connections[:i], connections[i+1:]...) + } else { + connections = nil + } +} + +func broadCastMessage(msg string, connection net.Conn) { + // отправка сообщения всем клиентам + for _, c := range connections { + if connection != c { + _, err := c.Write([]byte(msg)) + checkErr(err) + } + } + + msg = msg[:len(msg)-1] + fmt.Println(msg) +} + +func RunServer(port int) { + // net.Listen возвращает Listener переменную, + // которая является общим сетевым прослушивателем для потоковых протоколов + listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) + checkErr(err) + + defer listener.Close() + + for { + connection, err := listener.Accept() // ожидание подключения клиента к серверу + // Только после успешного вызова Accept()TCP-сервер может начать + // взаимодействовать с TCP-клиентами + if err != nil { + log.Print(err) + return + } + go handleConnection(connection) + } +} diff --git a/part_10/10.4/golang/todo-service/.vscode/settings.json b/part_10/10.4/golang/todo-service/.vscode/settings.json new file mode 100644 index 0000000..f465c5c --- /dev/null +++ b/part_10/10.4/golang/todo-service/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "yaml.schemas": { + "swaggerviewer:openapi": "file:///e%3A/code/golang/todo-service/todo-service-api.yml" + } +} \ No newline at end of file diff --git a/part_10/10.4/golang/todo-service/db/db.go b/part_10/10.4/golang/todo-service/db/db.go new file mode 100644 index 0000000..e098e42 --- /dev/null +++ b/part_10/10.4/golang/todo-service/db/db.go @@ -0,0 +1,98 @@ +package db + +import ( + _ "database/sql" + "fmt" + "log" + "os" + + "gorm.io/driver/sqlite" + "gorm.io/gorm" +) + +type SQLiteRepository struct { + db *gorm.DB +} + +func NewSQLiteRepository() *SQLiteRepository { + var db *gorm.DB + + if _, err := os.Stat(dbName); os.IsNotExist(err) { + db, err = gorm.Open(sqlite.Open(dbName), &gorm.Config{}) + if err != nil { + log.Fatal(err) + } + fmt.Println("DB isn't exist") + db.AutoMigrate(&Project{}, &Task{}) + putDefaultValuesToDB(db) + } else { + db, err = gorm.Open(sqlite.Open(dbName), &gorm.Config{}) + if err != nil { + log.Fatal(err) + } + fmt.Println("DB already exists") + } + + return &SQLiteRepository{ + db: db, + } +} + +func putDefaultValuesToDB(db *gorm.DB) { + firstProject := Project{ + Name: "Go", + Description: "Roadmap for learning Go", + } + secondProject := Project{ + Name: "One Year", + Description: "Tasks for the year", + } + db.Create(&firstProject) + db.Create(&secondProject) + db.Create(&Task{ + Name: "Variable", + Description: "Learning Go build-in variables", + Priority: 1, + Project: &firstProject, + }) + db.Create(&Task{ + Name: "Struct", + Description: "Learning use struct in OOP code", + Priority: 3, + Project: &firstProject, + }) + db.Create(&Task{ + Name: "Goroutine", + Description: "Learning concurrent programming", + Priority: 5, + Project: &firstProject, + }) + db.Create(&Task{ + Name: "DataBase", + Description: "How write app with db", + Priority: 1, + Project: &firstProject, + }) + db.Create(&Task{ + Name: "PhD", + Description: "Ph.D. in Technical Sciences", + Priority: 5, + Project: &secondProject, + }) + db.Create(&Task{ + Name: "Losing weight", + Description: "Exercise and eat less chocolate", + Priority: 2, + Project: &secondProject, + }) + db.Create(&Task{ + Name: "Пафос и превозмогание", + Description: "10к подписчиков на канале", + Priority: 2, + Project: &secondProject, + }) +} + +func (r *SQLiteRepository) Close() { + +} diff --git a/part_10/10.4/golang/todo-service/db/db_definition.go b/part_10/10.4/golang/todo-service/db/db_definition.go new file mode 100644 index 0000000..d6a42a3 --- /dev/null +++ b/part_10/10.4/golang/todo-service/db/db_definition.go @@ -0,0 +1,12 @@ +package db + +import "errors" + +const dbName = "todo.db" + +var ( + ErrDuplicate = errors.New("record already exists") + ErrNotExists = errors.New("row not exists") + ErrUpdateFailed = errors.New("update failed") + ErrDeleteFailed = errors.New("delete failed") +) diff --git a/part_10/10.4/golang/todo-service/db/models.go b/part_10/10.4/golang/todo-service/db/models.go new file mode 100644 index 0000000..e2f306f --- /dev/null +++ b/part_10/10.4/golang/todo-service/db/models.go @@ -0,0 +1,17 @@ +package db + +type Project struct { + ID int `json:"id" gorm:"primary_key;autoIncrement:true;not null"` + Name string `json:"name" gorm:"unique;not null"` + Description string `json:"description"` +} + +type Task struct { + ID int `json:"id" gorm:"primary_key;autoIncrement;not null"` + Name string `json:"name" gorm:"not null"` + Description string `json:"description" gorm:"not null"` + Priority uint8 `json:"priority" gorm:"not null"` + IsDone bool `json:"isDone" gorm:"not null"` + ProjectID int `json:"projectID" gorm:"not null"` + Project *Project `gorm:"foreignKey:ProjectID;references:ID"` +} diff --git a/part_10/10.4/golang/todo-service/db/projects_crud.go b/part_10/10.4/golang/todo-service/db/projects_crud.go new file mode 100644 index 0000000..5546660 --- /dev/null +++ b/part_10/10.4/golang/todo-service/db/projects_crud.go @@ -0,0 +1,49 @@ +package db + +import ( + "errors" + + "github.com/mattn/go-sqlite3" +) + +func (r *SQLiteRepository) AddProject(project Project) (*Project, error) { + tx := r.db.Create(&project) + if tx.Error != nil { + var sqliteErr sqlite3.Error + if errors.As(tx.Error, &sqliteErr) { + if errors.Is(sqliteErr.ExtendedCode, sqlite3.ErrConstraintUnique) { + return nil, ErrDuplicate + } + } + return nil, tx.Error + } + + return &project, nil +} + +func (r *SQLiteRepository) DeleteProject(projectID int) error { + tx := r.db.Delete(&Project{ID: projectID}) + if tx.Error != nil { + return tx.Error + } + + rowsAffected := tx.RowsAffected + if rowsAffected == 0 { + return ErrDeleteFailed + } + + return nil +} + +func (r *SQLiteRepository) GetAllProjects() ([]Project, error) { + var projects []Project + tx := r.db.Find(&projects) + if tx.Error != nil { + return nil, tx.Error + } + if tx.RowsAffected == 0 { + return nil, ErrNotExists + } + + return projects, nil +} diff --git a/part_10/10.4/golang/todo-service/db/tasks_crud.go b/part_10/10.4/golang/todo-service/db/tasks_crud.go new file mode 100644 index 0000000..9f8dc1d --- /dev/null +++ b/part_10/10.4/golang/todo-service/db/tasks_crud.go @@ -0,0 +1,73 @@ +package db + +import "errors" + +func (r *SQLiteRepository) AddTask(task Task) (*Task, error) { + tx := r.db.Create(&task) + if tx.Error != nil { + return nil, tx.Error + } + + return &task, nil +} + +func (r *SQLiteRepository) DeleteTask(taskID int) error { + tx := r.db.Delete(&Task{ID: taskID}) + if tx.Error != nil { + return tx.Error + } + + rowsAffected := tx.RowsAffected + if rowsAffected == 0 { + return ErrDeleteFailed + } + + return nil +} + +func (r *SQLiteRepository) GetAllTasks() (tasks []Task, err error) { + tx := r.db.Find(&tasks) + if tx.Error != nil { + return nil, tx.Error + } + if tx.RowsAffected == 0 { + return nil, ErrNotExists + } + + return +} + +func (r *SQLiteRepository) GetProjectTasks(projectID int) (tasks []Task, err error) { + if projectID == 0 { + return nil, errors.New("invalid updated ID") + } + + tx := r.db.Where("project_id", projectID).Find(&tasks) + if tx.Error != nil { + return nil, tx.Error + } + if tx.RowsAffected == 0 { + return nil, ErrNotExists + } + + return +} + +func (r *SQLiteRepository) TaskDone(taskId int) error { + if taskId == 0 { + return errors.New("invalid updated ID") + } + pjTask := &Task{ID: taskId} + tx := r.db.Find(&pjTask) + if tx.Error != nil { + return tx.Error + } + pjTask.IsDone = true + r.db.Save(&pjTask) + rowsAffected := tx.RowsAffected + if rowsAffected == 0 { + return ErrUpdateFailed + } + + return nil +} diff --git a/part_10/10.4/golang/todo-service/go.mod b/part_10/10.4/golang/todo-service/go.mod new file mode 100644 index 0000000..4445f4d --- /dev/null +++ b/part_10/10.4/golang/todo-service/go.mod @@ -0,0 +1,16 @@ +module golang/todo-service + +go 1.24 + +require ( + github.com/gorilla/mux v1.8.1 + github.com/mattn/go-sqlite3 v1.14.24 + gorm.io/driver/sqlite v1.5.7 +) + +require ( + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + golang.org/x/text v0.14.0 // indirect + gorm.io/gorm v1.25.12 // indirect +) diff --git a/part_10/10.4/golang/todo-service/go.sum b/part_10/10.4/golang/todo-service/go.sum new file mode 100644 index 0000000..3e6353e --- /dev/null +++ b/part_10/10.4/golang/todo-service/go.sum @@ -0,0 +1,16 @@ +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= +github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +gorm.io/driver/sqlite v1.5.7 h1:8NvsrhP0ifM7LX9G4zPB97NwovUakUxc+2V2uuf3Z1I= +gorm.io/driver/sqlite v1.5.7/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4= +gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde h1:9DShaph9qhkIYw7QF91I/ynrr4cOO2PZra2PFD7Mfeg= +gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= +gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= diff --git a/part_10/10.4/golang/todo-service/main.go b/part_10/10.4/golang/todo-service/main.go new file mode 100644 index 0000000..43717b7 --- /dev/null +++ b/part_10/10.4/golang/todo-service/main.go @@ -0,0 +1,20 @@ +package main + +import ( + "golang/todo-service/db" + "golang/todo-service/service" + "log" + "net/http" +) + +const PORT = "8080" + +func main() { + + rep := db.NewSQLiteRepository() + defer rep.Close() + + router := service.NewRouter(rep) + log.Printf("Server started") + log.Fatal(http.ListenAndServe(":"+PORT, router)) +} diff --git a/part_10/10.4/golang/todo-service/service/api_models.go b/part_10/10.4/golang/todo-service/service/api_models.go new file mode 100644 index 0000000..241c312 --- /dev/null +++ b/part_10/10.4/golang/todo-service/service/api_models.go @@ -0,0 +1,22 @@ +package service + +import "golang/todo-service/db" + +type ErrorResponse struct { + Code int `json:"code"` + Message string `json:"message"` +} + +type GoodResponse struct { + Code int `json:"code"` + Message string `json:"message"` + ID int `json:"id"` +} + +type ProjectsList struct { + Items []db.Project `json:"items,omitempty"` +} + +type TasksList struct { + Items []db.Task `json:"items,omitempty"` +} diff --git a/part_10/10.4/golang/todo-service/service/api_project.go b/part_10/10.4/golang/todo-service/service/api_project.go new file mode 100644 index 0000000..404b101 --- /dev/null +++ b/part_10/10.4/golang/todo-service/service/api_project.go @@ -0,0 +1,87 @@ +package service + +import ( + "encoding/json" + "golang/todo-service/db" + "io" + "net/http" + "strconv" + + "github.com/gorilla/mux" +) + +func deleteProject(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + params := mux.Vars(r) + + idStr, ok := params["id"] + if !ok { + errorResponse(w, ErrorResponse{http.StatusBadRequest, + "Validation Failed"}) + return + } + id, err := strconv.Atoi(idStr) + if err != nil { + errorResponse(w, ErrorResponse{http.StatusBadRequest, + "Validation Failed"}) + return + } + + err = repository.DeleteProject(id) + if err != nil { + errorResponse(w, ErrorResponse{http.StatusNotFound, + "Project not found"}) + return + } + w.WriteHeader(http.StatusOK) +} + +func addProject(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + var project db.Project + reqBody, err := io.ReadAll(r.Body) + if err == nil { + json.Unmarshal(reqBody, &project) + if project.Name == "" { + errorResponse(w, ErrorResponse{http.StatusBadRequest, + "Validation Failed"}) + return + } + + project.ID = 0 + project, err := repository.AddProject(project) + if err != nil { + errorResponse(w, ErrorResponse{http.StatusBadRequest, + "Project with that name already exists"}) + return + } + + goodResponse := GoodResponse{ + Code: 201, + Message: "Проект создан", + ID: project.ID, + } + jsonGoodResponse, _ := json.Marshal(goodResponse) + w.WriteHeader(http.StatusCreated) + w.Write(jsonGoodResponse) + return + } + errorResponse(w, ErrorResponse{http.StatusBadRequest, + "Validation Failed"}) +} + +func getProjects(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + + progects, err := repository.GetAllProjects() + if err != nil || len(progects) == 0 { + errorResponse(w, ErrorResponse{http.StatusNotFound, + "Projects not found"}) + return + } + + projectsList := ProjectsList{progects} + jsonGoodResponse, _ := json.Marshal(projectsList) + w.WriteHeader(http.StatusOK) + w.Write(jsonGoodResponse) +} diff --git a/part_10/10.4/golang/todo-service/service/api_task.go b/part_10/10.4/golang/todo-service/service/api_task.go new file mode 100644 index 0000000..6e1b594 --- /dev/null +++ b/part_10/10.4/golang/todo-service/service/api_task.go @@ -0,0 +1,153 @@ +package service + +import ( + "encoding/json" + "golang/todo-service/db" + "io" + "net/http" + "strconv" +) + +func deleteTask(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + queryStr := r.URL.Query() + + idStr, ok := queryStr["id"] + if !ok { + errorResponse(w, ErrorResponse{http.StatusBadRequest, + "Validation Failed"}) + return + } + if len(idStr) == 0 { + errorResponse(w, ErrorResponse{http.StatusBadRequest, + "Validation Failed"}) + return + } + + id, err := strconv.Atoi(idStr[0]) + if err != nil { + errorResponse(w, ErrorResponse{http.StatusBadRequest, + "Validation Failed"}) + return + } + + err = repository.DeleteTask(id) + if err != nil { + errorResponse(w, ErrorResponse{http.StatusNotFound, + "Task not found"}) + return + } + w.WriteHeader(http.StatusOK) +} + +func getTask(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + queryStr := r.URL.Query() + + idStr, ok := queryStr["projectID"] + if !ok { + tasks, err := repository.GetAllTasks() + if err != nil || len(tasks) == 0 { + errorResponse(w, ErrorResponse{http.StatusNotFound, + "Tasks not found"}) + return + } + // возвращаем все имеющиеся задачи + projectsList := TasksList{tasks} + jsonGoodResponse, _ := json.Marshal(projectsList) + w.WriteHeader(http.StatusOK) + w.Write(jsonGoodResponse) + return + } + + if len(idStr) == 0 { + errorResponse(w, ErrorResponse{http.StatusBadRequest, + "Validation Failed"}) + return + } + + id, err := strconv.Atoi(idStr[0]) + if err != nil { + errorResponse(w, ErrorResponse{http.StatusBadRequest, + "Validation Failed"}) + return + } + + tasks, err := repository.GetProjectTasks(id) + if err != nil || len(tasks) == 0 { + errorResponse(w, ErrorResponse{http.StatusNotFound, + "Tasks not found"}) + return + } + // возвращаем все задачи конкретного проекта + projectsList := TasksList{tasks} + jsonGoodResponse, _ := json.Marshal(projectsList) + w.WriteHeader(http.StatusOK) + w.Write(jsonGoodResponse) +} + +func addTask(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + var task db.Task + reqBody, err := io.ReadAll(r.Body) + if err == nil { + json.Unmarshal(reqBody, &task) + if task.Name == "" || task.ProjectID == 0 { + errorResponse(w, ErrorResponse{http.StatusBadRequest, + "Validation Failed"}) + return + } + + task.ID = 0 + task, err := repository.AddTask(task) + if err != nil { + errorResponse(w, ErrorResponse{http.StatusBadRequest, + "Validation Failed"}) + return + } + + goodResponse := GoodResponse{ + Code: 201, + Message: "Задача создана", + ID: task.ID, + } + jsonGoodResponse, _ := json.Marshal(goodResponse) + w.WriteHeader(http.StatusCreated) + w.Write(jsonGoodResponse) + return + } + errorResponse(w, ErrorResponse{http.StatusBadRequest, + "Validation Failed"}) +} + +func doneTask(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + queryStr := r.URL.Query() + + idStr, ok := queryStr["id"] + if !ok { + errorResponse(w, ErrorResponse{http.StatusBadRequest, + "Validation Failed"}) + return + } + if len(idStr) == 0 { + errorResponse(w, ErrorResponse{http.StatusBadRequest, + "Validation Failed"}) + return + } + + id, err := strconv.Atoi(idStr[0]) + if err != nil { + errorResponse(w, ErrorResponse{http.StatusBadRequest, + "Validation Failed"}) + return + } + + err = repository.TaskDone(id) + if err != nil { + errorResponse(w, ErrorResponse{http.StatusNotFound, + "Tasks not found"}) + return + } + w.WriteHeader(http.StatusOK) +} diff --git a/part_10/10.4/golang/todo-service/service/logger.go b/part_10/10.4/golang/todo-service/service/logger.go new file mode 100644 index 0000000..a1f80c9 --- /dev/null +++ b/part_10/10.4/golang/todo-service/service/logger.go @@ -0,0 +1,23 @@ +package service + +import ( + "log" + "net/http" + "time" +) + +func Logger(inner http.Handler, name string) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + + inner.ServeHTTP(w, r) + + log.Printf( + "%s %s %s %s", + r.Method, + r.RequestURI, + name, + time.Since(start), + ) + }) +} diff --git a/part_10/10.4/golang/todo-service/service/routers.go b/part_10/10.4/golang/todo-service/service/routers.go new file mode 100644 index 0000000..c9513a5 --- /dev/null +++ b/part_10/10.4/golang/todo-service/service/routers.go @@ -0,0 +1,102 @@ +package service + +import ( + "encoding/json" + "fmt" + "golang/todo-service/db" + "net/http" + + "github.com/gorilla/mux" +) + +type Route struct { + Name string // имя функции обработчика + Method string // тип HTTP-сообщения + Pattern string // шаблон пути + HandlerFunc http.HandlerFunc // ссылка на функцию обработчик + // сигнатура функции должна быть func(ResponseWriter, *Request) +} + +var repository *db.SQLiteRepository + +func NewRouter(rep *db.SQLiteRepository) *mux.Router { + repository = rep + router := mux.NewRouter().StrictSlash(true) + for _, route := range routes { + var handler http.Handler + handler = route.HandlerFunc + //оборачиваем функцию-обработчик в логгер + handler = Logger(route.HandlerFunc, route.Name) + // handler := route.HandlerFunc + // // // добавляем новый обработчик + router. //HandleFunc(route.Pattern, handler).Methods(route.Method) + Methods(route.Method). // тип HTTP-сообщения + Path(route.Pattern). // шаблон пути + Name(route.Name). // имя функции обработчика + Handler(handler) // ссылка на функцию обработчик + } + router.Use(mux.CORSMethodMiddleware(router)) + + return router +} + +func home(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "Hello Wold in REST API style!!!") +} + +var routes = []Route{ + { // домашняя страница + "home", + http.MethodGet, + "/api/v1/todo", + home, + }, + { // удаление проекта по id + "deleteProject", + http.MethodDelete, + "/api/v1/todo/project/del/{id}", + deleteProject, + }, + { // добавление проекта + "addProject", + http.MethodPost, + "/api/v1/todo/project", + addProject, + }, + { // получить все проекты + "getProjects", + http.MethodGet, + "/api/v1/todo/projects", + getProjects, + }, + { // удаление задачи + "deleteTask", + http.MethodDelete, + "/api/v1/todo/task", + deleteTask, + }, + { // получение всех задач или конкретного проекта + "getTask", + http.MethodGet, + "/api/v1/todo/task", + getTask, + }, + { // добавить задачу + "addTask", + http.MethodPost, + "/api/v1/todo/task", + addTask, + }, + { // изменение статуса задачи на «Выполнено» + "doneTask", + http.MethodPut, + "/api/v1/todo/task", + doneTask, + }, +} + +func errorResponse(w http.ResponseWriter, err ErrorResponse) { + jsonResponse, _ := json.Marshal(err) + w.WriteHeader(err.Code) + w.Write(jsonResponse) +} diff --git a/part_10/10.4/golang/todo-service/todo-service-api.yml b/part_10/10.4/golang/todo-service/todo-service-api.yml new file mode 100644 index 0000000..b256da3 --- /dev/null +++ b/part_10/10.4/golang/todo-service/todo-service-api.yml @@ -0,0 +1,429 @@ +openapi: 3.0.2 +info: + title: ToDo client-server api + description: | + Документация по описанию конечных точек сервера, посредством которых + происходит доступ к ресурсам + version: 1.0.0 +servers: +- url: http://127.0.0.1:8080/api/v1/todo + +tags: +- name: task +- name: project + +paths: + /project: + post: + tags: + - project + description: | + Добавление проекта + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Project' + responses: + "201": + description: Добавление прошло успешно. + content: + application/json: + schema: + $ref: '#/components/schemas/GoodResponse' + examples: + response: + value: |- + { + "code": 201, + "message": "Project created", + "id": 1 + } + "400": + description: Невалидная схема проекта или входные данные не верны. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + examples: + response: + value: |- + { + "code": 400, + "message": "Validation Failed" + } + + /project/del/{id}: + delete: + tags: + - project + description: | + Удалить проект + parameters: + - description: Идентификатор + in: path + name: id + required: true + schema: + type: integer + example: 1 + responses: + "200": + description: Удаление прошло успешно. + "400": + description: Невалидная схема проекта или входные данные не верны. + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + examples: + response: + value: |- + { + "code": 400, + "message": "Validation Failed" + } + "404": + description: Проект не найден. + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + examples: + response: + value: |- + { + "code": 404, + "message": "Project not found" + } + + /projects: + get: + tags: + - project + description: | + Получить список проектов + responses: + "200": + description: Запрос прошел успешно + content: + application/json: + schema: + $ref: "#/components/schemas/ProgectsList" + "404": + description: Проект не найден. + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + examples: + response: + value: |- + { + "code": 404, + "message": "Projects not found" + } + + /task: + put: + tags: + - task + description: | + Изменение статуса задачи + parameters: + - in: query + required: true + name: id + schema: + type: integer + example: 1 + responses: + "201": + description: Запрос прошел успешно + "400": + description: Невалидная схема задачи или входные данные не верны. + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + examples: + response: + value: |- + { + "code": 400, + "message": "Validation Failed" + } + "404": + description: Проект не найден. + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + examples: + response: + value: |- + { + "code": 404, + "message": "Tasks not found" + } + post: + tags: + - task + description: | + Добавление задачи + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/Task" + responses: + "201": + description: Добавление прошло успешно. + content: + application/json: + schema: + $ref: "#/components/schemas/GoodResponse" + examples: + response: + value: |- + { + "code": 201, + "message": "Task created", + "id": 1 + } + "400": + description: Невалидная схема задачи или входные данные не верны. + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + examples: + response: + value: |- + { + "code": 400, + "message": "Validation Failed" + } + get: + tags: + - task + description: | + Получение списка всех задач или конкретного проекта + parameters: + - in: query + name: projectID + schema: + type: integer + example: 1 + responses: + "200": + description: Запрос прошел успешно + content: + application/json: + schema: + $ref: "#/components/schemas/TasksList" + "400": + description: Невалидная схема задачи или входные данные не верны. + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + examples: + response: + value: |- + { + "code": 400, + "message": "Validation Failed" + } + "404": + description: Проект не найден. + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + examples: + response: + value: |- + { + "code": 404, + "message": "Tasks not found" + } + delete: + tags: + - task + description: | + Удаление задачи с заданным ID + parameters: + - in: query + required: true + name: id + schema: + type: integer + example: 1 + responses: + "200": + description: Запрос прошел успешно + "400": + description: Невалидная схема задачи или входные данные не верны. + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + examples: + response: + value: |- + { + "code": 400, + "message": "Validation Failed" + } + "404": + description: Задача не найдена. + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + examples: + response: + value: |- + { + "code": 404, + "message": "Task not found" + } + +components: + schemas: + Error: + required: + - code + - message + properties: + code: + type: integer + nullable: false + message: + type: string + nullable: false + + GoodResponse: + required: + - code + - id + - message + properties: + code: + type: integer + nullable: false + message: + type: string + nullable: false + id: + type: integer + nullable: false + example: + code: 0 + id: 6 + message: message + + Project: + required: + - description + - id + - name + type: object + properties: + id: + type: integer + description: id project + name: + type: string + description: Имя проекта + nullable: false + description: + type: string + description: Описание проекта + nullable: false + example: + id: 1 + name: Пафос и Превозмогание + description: Прожать батоны и вперед!!! + + ProgectsList: + type: object + properties: + items: + type: array + description: Список существующих проектов + nullable: false + items: + $ref: '#/components/schemas/Project' + example: + items: + - id: 1 + name: Пафос и Превозмогание + description: Прожать батоны и вперед!!! + - id: 1 + name: Пафос и Превозмогание + description: Прожать батоны и вперед!!! + + Task: + required: + - description + - id + - isDone + - name + - projectID + - priority + type: object + properties: + id: + type: integer + description: id task + name: + type: string + description: Имя задачи + nullable: false + description: + type: string + description: Описание задачи + nullable: false + priority: + type: integer + description: приоритет задачи + nullable: false + isDone: + type: boolean + description: Флаг о выполнении задачи + nullable: false + projectID: + type: integer + description: id task + nullable: false + example: + id: 1 + name: 10к подписчиков + description: Прожать батоны и вперед!!! + isDone: false + projectID: 1 + priority: 3 + + TasksList: + type: object + properties: + items: + type: array + description: Список существующих проектов + nullable: false + items: + $ref: '#/components/schemas/Task' + example: + items: + - id: 1 + name: 10к подписчиков + description: Прожать батоны и вперед!!! + isDone: false + projectID: 1 + - id: 1 + name: 10к подписчиков + description: Прожать батоны и вперед!!! + isDone: false + projectID: 1 \ No newline at end of file diff --git a/part_10/10.4/golang/todo-service/todo.db b/part_10/10.4/golang/todo-service/todo.db new file mode 100644 index 0000000..2915c0a Binary files /dev/null and b/part_10/10.4/golang/todo-service/todo.db differ diff --git a/part_11/11.1/golang/testing/calculator/calculator.go b/part_11/11.1/golang/testing/calculator/calculator.go new file mode 100644 index 0000000..085ef4d --- /dev/null +++ b/part_11/11.1/golang/testing/calculator/calculator.go @@ -0,0 +1,19 @@ +package calculator + +import "math" + +func Add(a, b int) int { + return a + b +} + +func Sub(a, b int) int { + return a - b +} + +func Mul(a, b int) int { + return a * b +} + +func Pow2(a int) int { + return int(math.Pow(float64(a), 2)) +} diff --git a/part_11/11.1/golang/testing/go.mod b/part_11/11.1/golang/testing/go.mod new file mode 100644 index 0000000..a878c85 --- /dev/null +++ b/part_11/11.1/golang/testing/go.mod @@ -0,0 +1,3 @@ +module golang/testing + +go 1.19 diff --git a/part_11/11.1/golang/testing/main.go b/part_11/11.1/golang/testing/main.go new file mode 100644 index 0000000..affe062 --- /dev/null +++ b/part_11/11.1/golang/testing/main.go @@ -0,0 +1,13 @@ +package main + +import ( + "fmt" + calc "golang/testing/calculator" +) + +func main() { + fmt.Println(calc.Add(4, 2)) // 6 + fmt.Println(calc.Sub(23, 12)) // 11 + fmt.Println(calc.Mul(5, 6)) // 30 + fmt.Println(calc.Pow2(5)) // 25 +} diff --git a/part_11/11.1/golang/testing/test/calculator_test.go b/part_11/11.1/golang/testing/test/calculator_test.go new file mode 100644 index 0000000..f636979 --- /dev/null +++ b/part_11/11.1/golang/testing/test/calculator_test.go @@ -0,0 +1,38 @@ +package test_test + +import ( + calc "golang/testing/calculator" + "testing" +) + +func TestAdd(t *testing.T) { + result := calc.Add(2, 5) + expected := 7 + if result != expected { + t.Errorf("result %d, expected %d", result, expected) + } +} + +func TestSub(t *testing.T) { + result := calc.Sub(15, 5) + expected := 10 + if result != expected { + t.Errorf("result %d, expected %d", result, expected) + } +} + +func TestMul(t *testing.T) { + result := calc.Mul(3, 6) + expected := 18 + if result != expected { + t.Errorf("result %d, expected %d", result, expected) + } +} + +func TestPow2(t *testing.T) { + result := calc.Pow2(3) + expected := 9 + if result != expected { + t.Errorf("result %d, expected %d", result, expected) + } +} diff --git a/part_11/11.2/golang/testing/calculator/calculator.go b/part_11/11.2/golang/testing/calculator/calculator.go new file mode 100644 index 0000000..085ef4d --- /dev/null +++ b/part_11/11.2/golang/testing/calculator/calculator.go @@ -0,0 +1,19 @@ +package calculator + +import "math" + +func Add(a, b int) int { + return a + b +} + +func Sub(a, b int) int { + return a - b +} + +func Mul(a, b int) int { + return a * b +} + +func Pow2(a int) int { + return int(math.Pow(float64(a), 2)) +} diff --git a/part_11/11.2/golang/testing/go.mod b/part_11/11.2/golang/testing/go.mod new file mode 100644 index 0000000..a878c85 --- /dev/null +++ b/part_11/11.2/golang/testing/go.mod @@ -0,0 +1,3 @@ +module golang/testing + +go 1.19 diff --git a/part_11/11.2/golang/testing/main.go b/part_11/11.2/golang/testing/main.go new file mode 100644 index 0000000..affe062 --- /dev/null +++ b/part_11/11.2/golang/testing/main.go @@ -0,0 +1,13 @@ +package main + +import ( + "fmt" + calc "golang/testing/calculator" +) + +func main() { + fmt.Println(calc.Add(4, 2)) // 6 + fmt.Println(calc.Sub(23, 12)) // 11 + fmt.Println(calc.Mul(5, 6)) // 30 + fmt.Println(calc.Pow2(5)) // 25 +} diff --git a/part_11/11.2/golang/testing/test/calculator_test.go b/part_11/11.2/golang/testing/test/calculator_test.go new file mode 100644 index 0000000..5faf730 --- /dev/null +++ b/part_11/11.2/golang/testing/test/calculator_test.go @@ -0,0 +1,70 @@ +package test_test + +import ( + calc "golang/testing/calculator" + "testing" +) + +type testData struct { + arg1, arg2, expected int +} + +type testPowData struct { + arg, expected int +} + +func TestAdd(t *testing.T) { + cases := []testData{ + {2, 3, 5}, + {10, 5, 15}, + {-8, -3, -11}, + } + for _, it := range cases { + result := calc.Add(it.arg1, it.arg2) + if result != it.expected { + t.Errorf("result %d, expected %d", result, it.expected) + } + } +} + +func TestSub(t *testing.T) { + cases := []testData{ + {2, 3, -1}, + {10, 5, 5}, + {-8, -3, -5}, + } + for _, it := range cases { + result := calc.Sub(it.arg1, it.arg2) + if result != it.expected { + t.Errorf("result %d, expected %d", result, it.expected) + } + } +} + +func TestMul(t *testing.T) { + cases := []testData{ + {2, 3, 6}, + {10, 5, 50}, + {-8, -3, 24}, + } + for _, it := range cases { + result := calc.Mul(it.arg1, it.arg2) + if result != it.expected { + t.Errorf("result %d, expected %d", result, it.expected) + } + } +} + +func TestPow2(t *testing.T) { + cases := []testPowData{ + {2, 4}, + {-2, 4}, + {3, 9}, + } + for _, it := range cases { + result := calc.Pow2(it.arg) + if result != it.expected { + t.Errorf("result %d, expected %d", result, it.expected) + } + } +} diff --git a/part_11/11.3/golang/testing/calculator/calculator.go b/part_11/11.3/golang/testing/calculator/calculator.go new file mode 100644 index 0000000..7849420 --- /dev/null +++ b/part_11/11.3/golang/testing/calculator/calculator.go @@ -0,0 +1,19 @@ +package calculator + +import "math" + +func Add(a, b int) int { + return a + b + 1 +} + +func Sub(a, b int) int { + return a - b +} + +func Mul(a, b int) int { + return a * b +} + +func Pow2(a int) int { + return int(math.Pow(float64(a), 2)) +} diff --git a/part_11/11.3/golang/testing/go.mod b/part_11/11.3/golang/testing/go.mod new file mode 100644 index 0000000..a878c85 --- /dev/null +++ b/part_11/11.3/golang/testing/go.mod @@ -0,0 +1,3 @@ +module golang/testing + +go 1.19 diff --git a/part_11/11.3/golang/testing/main.go b/part_11/11.3/golang/testing/main.go new file mode 100644 index 0000000..affe062 --- /dev/null +++ b/part_11/11.3/golang/testing/main.go @@ -0,0 +1,13 @@ +package main + +import ( + "fmt" + calc "golang/testing/calculator" +) + +func main() { + fmt.Println(calc.Add(4, 2)) // 6 + fmt.Println(calc.Sub(23, 12)) // 11 + fmt.Println(calc.Mul(5, 6)) // 30 + fmt.Println(calc.Pow2(5)) // 25 +} diff --git a/part_11/11.3/golang/testing/test/calculator_test.go b/part_11/11.3/golang/testing/test/calculator_test.go new file mode 100644 index 0000000..00ce875 --- /dev/null +++ b/part_11/11.3/golang/testing/test/calculator_test.go @@ -0,0 +1,76 @@ +package test_test + +import ( + "fmt" + calc "golang/testing/calculator" + "testing" +) + +type testData struct { + arg1, arg2, expected int +} + +type testPowData struct { + arg, expected int +} + +func TestAdd(t *testing.T) { + cases := []testData{ + {2, 3, 5}, + {10, 5, 15}, + {-8, -3, -11}, + } + for _, it := range cases { + t.Run( + fmt.Sprintf("%d+%d=%d", it.arg1, it.arg2, it.expected), // имя подтеста + func(t *testing.T) { // подтест + result := calc.Add(it.arg1, it.arg2) + if result != it.expected { + t.Errorf("result %d, expected %d", result, it.expected) + } + }, + ) + } +} + +func TestSub(t *testing.T) { + cases := []testData{ + {2, 3, -1}, + {10, 5, 5}, + {-8, -3, -5}, + } + for _, it := range cases { + result := calc.Sub(it.arg1, it.arg2) + if result != it.expected { + t.Errorf("result %d, expected %d", result, it.expected) + } + } +} + +func TestMul(t *testing.T) { + cases := []testData{ + {2, 3, 6}, + {10, 5, 50}, + {-8, -3, 24}, + } + for _, it := range cases { + result := calc.Mul(it.arg1, it.arg2) + if result != it.expected { + t.Errorf("result %d, expected %d", result, it.expected) + } + } +} + +func TestPow2(t *testing.T) { + cases := []testPowData{ + {2, 4}, + {-2, 4}, + {3, 9}, + } + for _, it := range cases { + result := calc.Pow2(it.arg) + if result != it.expected { + t.Errorf("result %d, expected %d", result, it.expected) + } + } +} diff --git a/part_11/11.4/golang/testing/calculator/calculator.go b/part_11/11.4/golang/testing/calculator/calculator.go new file mode 100644 index 0000000..7849420 --- /dev/null +++ b/part_11/11.4/golang/testing/calculator/calculator.go @@ -0,0 +1,19 @@ +package calculator + +import "math" + +func Add(a, b int) int { + return a + b + 1 +} + +func Sub(a, b int) int { + return a - b +} + +func Mul(a, b int) int { + return a * b +} + +func Pow2(a int) int { + return int(math.Pow(float64(a), 2)) +} diff --git a/part_11/11.4/golang/testing/calculator/calculator_bench_test.go b/part_11/11.4/golang/testing/calculator/calculator_bench_test.go new file mode 100644 index 0000000..202b939 --- /dev/null +++ b/part_11/11.4/golang/testing/calculator/calculator_bench_test.go @@ -0,0 +1,15 @@ +package calculator + +import "testing" + +func BenchmarkMul(b *testing.B) { + for i := 0; i < b.N; i++ { + Mul(5, 10) + } +} + +func BenchmarkPow2(b *testing.B) { + for i := 0; i < b.N; i++ { + Pow2(5) + } +} diff --git a/part_11/11.4/golang/testing/calculator/calculator_test.go b/part_11/11.4/golang/testing/calculator/calculator_test.go new file mode 100644 index 0000000..cf28a6e --- /dev/null +++ b/part_11/11.4/golang/testing/calculator/calculator_test.go @@ -0,0 +1,41 @@ +package calculator + +import ( + "testing" +) + +type testData struct { + arg1, arg2, expected int +} + +type testPowData struct { + arg, expected int +} + +func TestSub(t *testing.T) { + cases := []testData{ + {2, 3, -1}, + {10, 5, 5}, + {-8, -3, -5}, + } + for _, it := range cases { + result := Sub(it.arg1, it.arg2) + if result != it.expected { + t.Errorf("result %d, expected %d", result, it.expected) + } + } +} + +func TestPow2(t *testing.T) { + cases := []testPowData{ + {2, 4}, + {-2, 4}, + {3, 9}, + } + for _, it := range cases { + result := Pow2(it.arg) + if result != it.expected { + t.Errorf("result %d, expected %d", result, it.expected) + } + } +} diff --git a/part_11/11.4/golang/testing/go.mod b/part_11/11.4/golang/testing/go.mod new file mode 100644 index 0000000..a878c85 --- /dev/null +++ b/part_11/11.4/golang/testing/go.mod @@ -0,0 +1,3 @@ +module golang/testing + +go 1.19 diff --git a/part_11/11.4/golang/testing/main.go b/part_11/11.4/golang/testing/main.go new file mode 100644 index 0000000..affe062 --- /dev/null +++ b/part_11/11.4/golang/testing/main.go @@ -0,0 +1,13 @@ +package main + +import ( + "fmt" + calc "golang/testing/calculator" +) + +func main() { + fmt.Println(calc.Add(4, 2)) // 6 + fmt.Println(calc.Sub(23, 12)) // 11 + fmt.Println(calc.Mul(5, 6)) // 30 + fmt.Println(calc.Pow2(5)) // 25 +} diff --git a/part_11/11.5/golang/testing/calculator/calculator.go b/part_11/11.5/golang/testing/calculator/calculator.go new file mode 100644 index 0000000..7849420 --- /dev/null +++ b/part_11/11.5/golang/testing/calculator/calculator.go @@ -0,0 +1,19 @@ +package calculator + +import "math" + +func Add(a, b int) int { + return a + b + 1 +} + +func Sub(a, b int) int { + return a - b +} + +func Mul(a, b int) int { + return a * b +} + +func Pow2(a int) int { + return int(math.Pow(float64(a), 2)) +} diff --git a/part_11/11.5/golang/testing/calculator/calculator_test.go b/part_11/11.5/golang/testing/calculator/calculator_test.go new file mode 100644 index 0000000..cf28a6e --- /dev/null +++ b/part_11/11.5/golang/testing/calculator/calculator_test.go @@ -0,0 +1,41 @@ +package calculator + +import ( + "testing" +) + +type testData struct { + arg1, arg2, expected int +} + +type testPowData struct { + arg, expected int +} + +func TestSub(t *testing.T) { + cases := []testData{ + {2, 3, -1}, + {10, 5, 5}, + {-8, -3, -5}, + } + for _, it := range cases { + result := Sub(it.arg1, it.arg2) + if result != it.expected { + t.Errorf("result %d, expected %d", result, it.expected) + } + } +} + +func TestPow2(t *testing.T) { + cases := []testPowData{ + {2, 4}, + {-2, 4}, + {3, 9}, + } + for _, it := range cases { + result := Pow2(it.arg) + if result != it.expected { + t.Errorf("result %d, expected %d", result, it.expected) + } + } +} diff --git a/part_11/11.5/golang/testing/go.mod b/part_11/11.5/golang/testing/go.mod new file mode 100644 index 0000000..a878c85 --- /dev/null +++ b/part_11/11.5/golang/testing/go.mod @@ -0,0 +1,3 @@ +module golang/testing + +go 1.19 diff --git a/part_11/11.5/golang/testing/main.go b/part_11/11.5/golang/testing/main.go new file mode 100644 index 0000000..affe062 --- /dev/null +++ b/part_11/11.5/golang/testing/main.go @@ -0,0 +1,13 @@ +package main + +import ( + "fmt" + calc "golang/testing/calculator" +) + +func main() { + fmt.Println(calc.Add(4, 2)) // 6 + fmt.Println(calc.Sub(23, 12)) // 11 + fmt.Println(calc.Mul(5, 6)) // 30 + fmt.Println(calc.Pow2(5)) // 25 +} diff --git a/part_11/11.6/1.go b/part_11/11.6/1.go new file mode 100644 index 0000000..0156ac5 --- /dev/null +++ b/part_11/11.6/1.go @@ -0,0 +1,36 @@ +package main + +import ( + "fmt" + + "github.com/jaswdr/faker" +) + +func main() { + faker := faker.New() + + fmt.Println("----------Names----------") + for i := 0; i < 3; i++ { + fmt.Println(faker.Person().Name()) + } + fmt.Println("----------Beer----------") + for i := 0; i < 3; i++ { + fmt.Println(faker.Beer().Name()) + } + fmt.Println("----------Address----------") + for i := 0; i < 3; i++ { + fmt.Println(faker.Address().Address()) + } + fmt.Println("----------Country----------") + for i := 0; i < 3; i++ { + fmt.Println(faker.Address().Country()) + } + fmt.Println("----------Email----------") + for i := 0; i < 3; i++ { + fmt.Println(faker.Internet().Email()) + } + fmt.Println("-----Phone Number--------") + for i := 0; i < 3; i++ { + fmt.Println(faker.Phone().Number()) + } +} diff --git a/part_2/2.5.1/1.go b/part_2/2.5.1/1.go new file mode 100644 index 0000000..29f7b2b --- /dev/null +++ b/part_2/2.5.1/1.go @@ -0,0 +1,14 @@ +package main + +import "fmt" + +func main() { + t := 20 + if t >= 30 { + fmt.Println("Надеть шорты") + } else { + fmt.Println("Надеть брюки") + } +} + +// Надеть брюки diff --git a/part_2/2.5.1/2.go b/part_2/2.5.1/2.go new file mode 100644 index 0000000..b34129f --- /dev/null +++ b/part_2/2.5.1/2.go @@ -0,0 +1,13 @@ +package main + +import "fmt" + +func main() { + sun := true // поменяйте на false и снова запустите приложение + if !sun { + fmt.Println("Взять зонт") + } + fmt.Println("Выйти на улицу") +} + +// Выйти на улицу diff --git a/part_2/2.5.1/3.go b/part_2/2.5.1/3.go new file mode 100644 index 0000000..8dbc03c --- /dev/null +++ b/part_2/2.5.1/3.go @@ -0,0 +1,18 @@ +package main + +import "fmt" + +func main() { + var value int = 15 + if value > 0 && value < 10 { + fmt.Println("Число входит в диапазон от 0 до 10") + } else if value > 10 && value < 20 { + fmt.Println("Число входит в диапазон от 10 до 20") + } else if value > 20 && value < 30 { + fmt.Println("Число входит в диапазон от 20 до 30") + } else { + fmt.Println("Значение > 30") + } +} + +// Число входит в диапазон от 10 до 20 diff --git a/part_2/2.5.1/4.go b/part_2/2.5.1/4.go new file mode 100644 index 0000000..d05bf75 --- /dev/null +++ b/part_2/2.5.1/4.go @@ -0,0 +1,22 @@ +package main + +import "fmt" + +func main() { + var value int = 15 + if value > 30 { + if value < 50 { + fmt.Println("30 < value < 50") + } else { + fmt.Println("30 < value >= 50") + } + } else { + if value > 10 { + fmt.Println("30 >= value >= 10") + } else { + fmt.Println("30 >= value < 10") + } + } +} + +// 30 >= value >= 10 diff --git a/part_2/2.5.1/5.go b/part_2/2.5.1/5.go new file mode 100644 index 0000000..1acfbf8 --- /dev/null +++ b/part_2/2.5.1/5.go @@ -0,0 +1,13 @@ +package main + +import "fmt" + +func main() { + if value := 15; value > 30 { + fmt.Println("30 < value") + } else { + fmt.Println("30 >= value") + } +} + +// 30 >= value diff --git a/part_2/2.5.2/1.go b/part_2/2.5.2/1.go new file mode 100644 index 0000000..3c7618e --- /dev/null +++ b/part_2/2.5.2/1.go @@ -0,0 +1,19 @@ +package main + +import "fmt" + +func main() { + value := 2 + switch value { + case 2: + fmt.Println("2") + fmt.Printf("%d + 2 = %d", value, value+2) + case 4: + fmt.Println("4") + default: + fmt.Println("8") + } +} + +// 2 +// 2 + 2 = 4 diff --git a/part_2/2.5.2/2.go b/part_2/2.5.2/2.go new file mode 100644 index 0000000..df1408e --- /dev/null +++ b/part_2/2.5.2/2.go @@ -0,0 +1,20 @@ +package main + +import "fmt" + +func main() { + value := 2 + switch value := 4; value { + case 2: + fmt.Println("2") + fmt.Printf("%d + 2 = %d", value, value+2) + case 4: + fmt.Println("4") + default: + fmt.Println("8") + } + fmt.Printf("value = %d", value) +} + +// 4 +// value = 2 diff --git a/part_2/2.5.2/3.go b/part_2/2.5.2/3.go new file mode 100644 index 0000000..e089a16 --- /dev/null +++ b/part_2/2.5.2/3.go @@ -0,0 +1,15 @@ +package main + +import "fmt" + +func main() { + name := "Alex" + switch name { + case "Stanislav": + fmt.Println("Admin") + case "Maxim", "Alex", "Bill": + fmt.Println("Employee") + } +} + +// Employee diff --git a/part_2/2.5.2/4.go b/part_2/2.5.2/4.go new file mode 100644 index 0000000..361ba5b --- /dev/null +++ b/part_2/2.5.2/4.go @@ -0,0 +1,17 @@ +package main + +import "fmt" + +func main() { + name := "Stanislav" + switch name { + case "Stanislav": + fmt.Println("Admin") + fallthrough + case "Maxim", "Alex", "Bill": + fmt.Println("Employee") + } +} + +// Admin +// Employee diff --git a/part_2/2.5.2/5.go b/part_2/2.5.2/5.go new file mode 100644 index 0000000..68cc80d --- /dev/null +++ b/part_2/2.5.2/5.go @@ -0,0 +1,17 @@ +package main + +import "fmt" + +func main() { + name := "Stanislav" + switch name { + case "Stanislav": + fmt.Println("Admin") + break + fallthrough + case "Maxim", "Alex", "Bill": + fmt.Println("Employee") + } +} + +// Admin diff --git a/part_2/2.5.2/6.go b/part_2/2.5.2/6.go new file mode 100644 index 0000000..346d9ac --- /dev/null +++ b/part_2/2.5.2/6.go @@ -0,0 +1,25 @@ +package main + +import "fmt" + +func main() { + var value int = 5 + switch { + case value > 30: + switch { + case value < 50: + fmt.Println("30 < value < 50") + default: + fmt.Println("30 < value >= 50") + } + case value < 30: + switch { + case value > 10: + fmt.Println("30 >= value >= 10") + default: + fmt.Println("30 >= value < 10") + } + } +} + +// 30 >= value < 10 diff --git a/part_2/2.6/1.go b/part_2/2.6/1.go new file mode 100644 index 0000000..152d08e --- /dev/null +++ b/part_2/2.6/1.go @@ -0,0 +1,10 @@ +package main + +import "fmt" + +func main() { + value := 2 + for i := 0; i < 10; i++ { + fmt.Printf("%d * %d = %d\n", value, i, value*i) + } +} diff --git a/part_2/2.6/2.go b/part_2/2.6/2.go new file mode 100644 index 0000000..16fb1a7 --- /dev/null +++ b/part_2/2.6/2.go @@ -0,0 +1,19 @@ +package main + +import ( + "fmt" + "strconv" +) + +func main() { + str := "" + i := 0 + for { + str += strconv.Itoa(i) + if i >= 5 { + break + } + i++ + } + fmt.Println(str) // 012345 +} diff --git a/part_2/2.6/3.go b/part_2/2.6/3.go new file mode 100644 index 0000000..d2e73b4 --- /dev/null +++ b/part_2/2.6/3.go @@ -0,0 +1,16 @@ +package main + +import ( + "fmt" + "strconv" +) + +func main() { + str := "" + i := 0 + for i <= 5 { + str += strconv.Itoa(i) + i++ + } + fmt.Println(str) // 012345 +} diff --git a/part_2/2.6/4.go b/part_2/2.6/4.go new file mode 100644 index 0000000..b04870a --- /dev/null +++ b/part_2/2.6/4.go @@ -0,0 +1,14 @@ +package main + +import "fmt" + +func main() { + i := 13 + for i > 0 { + i-- + if i%2 == 0 { + continue + } + fmt.Printf("%d ", i) + } +} diff --git a/part_2/2.6/5.go b/part_2/2.6/5.go new file mode 100644 index 0000000..81f8252 --- /dev/null +++ b/part_2/2.6/5.go @@ -0,0 +1,27 @@ +package main + +import "fmt" + +func main() { + for i := 0; i < 2; i++ { + for j := 0; j < 3; j++ { + if i == j { + continue + } + fmt.Printf("%d %d || ", i, j) + } + } + // 0 1 || 0 2 || 1 0 || 1 2 || + + fmt.Println() + for i := 0; i < 2; i++ { + for j := 0; j < 3; j++ { + if i == j { + break + } + fmt.Printf("%d %d || ", i, j) + } + } + fmt.Println("Oo") + // 1 0 || Oo +} diff --git a/part_2/2.6/6.go b/part_2/2.6/6.go new file mode 100644 index 0000000..a8d54ad --- /dev/null +++ b/part_2/2.6/6.go @@ -0,0 +1,11 @@ +package main + +import "fmt" + +func main() { + array := [4]int{2, 5, 6, 0} + for i := 0; i < len(array); i++ { + array[i] += 3 + fmt.Printf("%d ", array[i]) + } +} diff --git a/part_2/2.6/7.go b/part_2/2.6/7.go new file mode 100644 index 0000000..bf8cd6e --- /dev/null +++ b/part_2/2.6/7.go @@ -0,0 +1,14 @@ +package main + +import "fmt" + +func main() { + array := [4]int{2, 5, 6, 0} + for i, v := range array { + v += 3 + fmt.Printf("%d) %d || ", i, v) + } + // 0) 5 || 1) 8 || 2) 9 || 3) 3 || + fmt.Println() + fmt.Println(array) // [2 5 6 0] +} diff --git a/part_2/2.6/8.go b/part_2/2.6/8.go new file mode 100644 index 0000000..a0e0a02 --- /dev/null +++ b/part_2/2.6/8.go @@ -0,0 +1,11 @@ +package main + +import "fmt" + +func main() { + array := [4]int{2, 5, 6, 0} + for i := range array { + array[i] += 3 + } + fmt.Println(array) // [5 8 9 3] +} diff --git a/part_2/2.6/9.go b/part_2/2.6/9.go new file mode 100644 index 0000000..c6d21d2 --- /dev/null +++ b/part_2/2.6/9.go @@ -0,0 +1,15 @@ +package main + +import "fmt" + +func main() { + myMap := map[int]string{ + 1: "Alex", + 2: "Maxim", + 200: "Jon", + } + + for i, v := range myMap { + fmt.Printf("key = %d, value = %s\n", i, v) + } +} diff --git a/part_2/2.7/1.go b/part_2/2.7/1.go new file mode 100644 index 0000000..046c616 --- /dev/null +++ b/part_2/2.7/1.go @@ -0,0 +1,11 @@ +package main + +import "fmt" + +func main() { + fmt.Println(1) // 1 + goto myLable + fmt.Println(2) +myLable: // метка для безусловного перехода + fmt.Println(3) // 3 +} diff --git a/part_2/2.7/2.go b/part_2/2.7/2.go new file mode 100644 index 0000000..c18ca5f --- /dev/null +++ b/part_2/2.7/2.go @@ -0,0 +1,16 @@ +package main + +import "fmt" + +func main() { + test() + fmt.Println(1) + goto myLable + fmt.Println(2) +myLable: + fmt.Println(3) +} + +func test() { + goto myLable // error: label myLable not defined +} diff --git a/part_2/2.7/3.go b/part_2/2.7/3.go new file mode 100644 index 0000000..0830874 --- /dev/null +++ b/part_2/2.7/3.go @@ -0,0 +1,10 @@ +package main + +import "fmt" + +func main() { +myLable: // бесконечный цикл + fmt.Println(1) + goto myLable + fmt.Println(2) +} diff --git a/part_3/3.1/1.go b/part_3/3.1/1.go new file mode 100644 index 0000000..b1a70c1 --- /dev/null +++ b/part_3/3.1/1.go @@ -0,0 +1,15 @@ +package main + +import "fmt" + +func main() { + hello() // вызов функции hello + fmt.Println("exit") +} + +func hello() { + fmt.Println("Hello World!") +} + +// Hello World! +// exit diff --git a/part_3/3.1/2.go b/part_3/3.1/2.go new file mode 100644 index 0000000..9e9b046 --- /dev/null +++ b/part_3/3.1/2.go @@ -0,0 +1,15 @@ +package main + +import "fmt" + +func main() { + add(3, 5) +} + +func add(a int, b int) { + fmt.Println(a + b) // 8 +} + +// func add(a, b int) { +// fmt.Println(a + b) +// } diff --git a/part_3/3.1/3.go b/part_3/3.1/3.go new file mode 100644 index 0000000..35b053d --- /dev/null +++ b/part_3/3.1/3.go @@ -0,0 +1,13 @@ +package main + +import "fmt" + +func main() { + userInfo(3, 5, "Alex") +} + +func userInfo(age, exp int, name string) { + fmt.Printf("User name: %s, age: %d, exp years: %d", name, age, exp) +} + +// User name: Alex, age: 3, exp years: 5 diff --git a/part_3/3.1/4.go b/part_3/3.1/4.go new file mode 100644 index 0000000..b3c3ebd --- /dev/null +++ b/part_3/3.1/4.go @@ -0,0 +1,11 @@ +package main + +import "fmt" + +func main() { + fmt.Println(userInfo(3, 5, "Alex")) // User name: Alex, age: 3, exp years: 5 +} + +func userInfo(age, exp int, name string) string { + return fmt.Sprintf("User name: %s, age: %d, exp year: %d", name, age, exp) +} diff --git a/part_3/3.1/5.go b/part_3/3.1/5.go new file mode 100644 index 0000000..4ecaca1 --- /dev/null +++ b/part_3/3.1/5.go @@ -0,0 +1,24 @@ +package main + +import "fmt" + +func main() { + rez, check := add(10, 8) + fmt.Printf("a + b = %d, a > b = %t", rez, check) +} + +func add(a, b int) (int, bool) { + return a + b, a > b +} + +// a + b = 18, a > b = true + +// func main() { +// rez := add(10, 8) // assignment mismatch: 1 variable but add returns 2 values +// fmt.Printf("a + b = %d", rez) +// } + +// func main() { +// rez, _ := add(10, 8) +// fmt.Printf("a + b = %d", rez) // a + b = 18 +// } diff --git a/part_3/3.1/6.go b/part_3/3.1/6.go new file mode 100644 index 0000000..eb66397 --- /dev/null +++ b/part_3/3.1/6.go @@ -0,0 +1,17 @@ +package main + +import "fmt" + +func main() { + rez, check := add(10, 8) + fmt.Printf("a + b = %d, a > b = %t", rez, check) +} + +func add(a, b int) (rez int, check bool) { + rez = a + b + check = a > b + return // аналогично return rez, check + +} + +// a + b = 18, a > b = true diff --git a/part_3/3.1/7.go b/part_3/3.1/7.go new file mode 100644 index 0000000..64e7c0d --- /dev/null +++ b/part_3/3.1/7.go @@ -0,0 +1,17 @@ +package main + +import "fmt" + +func main() { + fmt.Printf("Sum = %d", myFunc(3, 5, 9, 25, -10)) +} + +func myFunc(values ...int) (sum int) { + // переменную values рассматриваем как срез []int + for _, value := range values { + sum += value + } + return +} + +// Sum = 32 diff --git a/part_3/3.1/8.go b/part_3/3.1/8.go new file mode 100644 index 0000000..4eb7871 --- /dev/null +++ b/part_3/3.1/8.go @@ -0,0 +1,14 @@ +package main + +import "fmt" + +func main() { + sum := func(values ...int) (sum int) { // объявление функции + // переменную values рассматриваем как срез []int + for _, value := range values { + sum += value + } + return + }(3, 5, 9, 25, -10) // вызов функции + fmt.Printf("Sum = %d", sum) // Sum = 32 +} diff --git a/part_3/3.1/9.go b/part_3/3.1/9.go new file mode 100644 index 0000000..ad982ae --- /dev/null +++ b/part_3/3.1/9.go @@ -0,0 +1,34 @@ +package main + +import ( + "fmt" + "math/rand" + "time" +) + +// генератор случайных чисел +var generator = rand.New(rand.NewSource(time.Now().UnixNano())) + +func sliceCreator1(size int16) (slice *[]int16) { + slice = new([]int16) + *slice = make([]int16, size, size+10) + for i := range *slice { + (*slice)[i] += int16(generator.Int()) + } + return +} + +func sliceCreator2(size int16) *[]int16 { + slice := make([]int16, size, size+10) + for i := range slice { + slice[i] += int16(generator.Int()) + } + return &slice +} + +func main() { + slice := sliceCreator1(7) + fmt.Println(*slice) // [-22201 -30245 6682 28346 23159 -28589 16762] + slice = sliceCreator2(5) + fmt.Println(*slice) // [3896 28732 -30834 1722 -14725] +} diff --git a/part_3/3.10/1.go b/part_3/3.10/1.go new file mode 100644 index 0000000..6d91ceb --- /dev/null +++ b/part_3/3.10/1.go @@ -0,0 +1,20 @@ +package main + +import "fmt" + +func createGenerator(start int, end int) chan int { + ch := make(chan int, end-start) + go func(ch chan int) { + for i := start; i <= end; i++ { + ch <- i // помещение значения в канал + } + close(ch) + }(ch) + return ch +} + +func main() { + for it := range createGenerator(1, 10) { + fmt.Printf("%d || ", it) + } +} diff --git a/part_3/3.10/2.go b/part_3/3.10/2.go new file mode 100644 index 0000000..691185c --- /dev/null +++ b/part_3/3.10/2.go @@ -0,0 +1,25 @@ +package main + +import "fmt" + +func createGenerator(start int, end int) chan int { + ch := make(chan int, end-start) + go func(ch chan int) { + for i := start; i <= end; i++ { + ch <- i // помещение значения в канал + } + close(ch) + }(ch) + return ch +} + +func main() { + generator := createGenerator(4, 8) + for { + value := <-generator // распаковка значения из канала в переменную + fmt.Printf("%d || ", value) + if len(generator) <= 0 { // проверка на выход из бесконечного цикла + break + } + } +} diff --git a/part_3/3.11/1.go b/part_3/3.11/1.go new file mode 100644 index 0000000..031f175 --- /dev/null +++ b/part_3/3.11/1.go @@ -0,0 +1,12 @@ +package main + +import "fmt" + +func main() { + for i := 0; i < 3; i++ { + defer fmt.Printf("%d ", i) + } +} + +// Finish! +// 2 1 0 diff --git a/part_3/3.11/2.go b/part_3/3.11/2.go new file mode 100644 index 0000000..d361ebc --- /dev/null +++ b/part_3/3.11/2.go @@ -0,0 +1,13 @@ +package main + +import "fmt" + +func main() { + defer fmt.Printf("%d ", 0) + defer fmt.Printf("%d ", 1) + defer fmt.Printf("%d ", 2) + fmt.Println("Finish!") +} + +// Finish! +// 2 1 0 diff --git a/part_3/3.2/1.go b/part_3/3.2/1.go new file mode 100644 index 0000000..684f2df --- /dev/null +++ b/part_3/3.2/1.go @@ -0,0 +1,19 @@ +package main + +import "fmt" + +func main() { + array := [4]float64{2.4, 5.6, 8.1, 9.22} + myFunc(array) + fmt.Printf("Array in main: %v\n", array) +} + +func myFunc(array [4]float64) { + for i := range array { + array[i] += 2.33 + } + fmt.Printf("Array in myFunc: %v\n", array) +} + +// Array in myFunc: [4.73 7.93 10.43 11.55] +// Array in main: [2.4 5.6 8.1 9.22] diff --git a/part_3/3.2/2.go b/part_3/3.2/2.go new file mode 100644 index 0000000..0682392 --- /dev/null +++ b/part_3/3.2/2.go @@ -0,0 +1,19 @@ +package main + +import "fmt" + +func main() { + array := [4]float64{2.4, 5.6, 8.1, 9.22} + myFunc(&array) + fmt.Printf("Array in main: %v\n", array) +} + +func myFunc(array *[4]float64) { + for i := range array { + array[i] += 2.33 + } + fmt.Printf("Array in myFunc: %v\n", *array) +} + +// Array in myFunc: [4.73 7.93 10.43 11.55] +// Array in main: [4.73 7.93 10.43 11.55] diff --git a/part_3/3.2/3.go b/part_3/3.2/3.go new file mode 100644 index 0000000..fc1dc99 --- /dev/null +++ b/part_3/3.2/3.go @@ -0,0 +1,19 @@ +package main + +import "fmt" + +func main() { + array := []float64{2.4, 5.6, 8.1, 9.22} + myFunc(&array) + fmt.Printf("Array in main: %v\n", array) +} + +func myFunc(array *[]float64) { + for i := range *array { + (*array)[i] += 1.5 + } + fmt.Printf("Array in myFunc: %v\n", *array) +} + +// Array in myFunc: [3.9 7.1 9.6 10.72] +// Array in main: [3.9 7.1 9.6 10.72] diff --git a/part_3/3.2/4.go b/part_3/3.2/4.go new file mode 100644 index 0000000..a41586e --- /dev/null +++ b/part_3/3.2/4.go @@ -0,0 +1,15 @@ +package main + +import "fmt" + +func main() { + a, b, rez := 10, 13, 0 + add(a, b, &rez) + fmt.Printf("%d + %d = %d\n", a, b, rez) +} + +func add(a, b int, rez *int) { + *rez = a + b +} + +// 10 + 13 = 23 diff --git a/part_3/3.2/5.go b/part_3/3.2/5.go new file mode 100644 index 0000000..1297a97 --- /dev/null +++ b/part_3/3.2/5.go @@ -0,0 +1,35 @@ +package main + +import "fmt" + +func find1(slice *[]int, value int, check *bool) { + *check = false + for i := range *slice { + if (*slice)[i] == value { + *check = true + break + } + } +} + +func find2(slice *[]int, value int) bool { + for i := range *slice { + if (*slice)[i] == value { + return true + } + } + return false +} + +func main() { + slice := []int{2, 4, 5, 7, 103, 55} + var check bool + value := 2 + find1(&slice, value, &check) + fmt.Printf("%d contains in slice? %t\n", value, check) + value = 22 + fmt.Printf("%d contains in slice? %t\n", value, find2(&slice, value)) +} + +// 2 contains in slice? true +// 22 contains in slice? false diff --git a/part_3/3.3/1.go b/part_3/3.3/1.go new file mode 100644 index 0000000..bc266fe --- /dev/null +++ b/part_3/3.3/1.go @@ -0,0 +1,18 @@ +package main + +import "fmt" + +func myFunc(value map[string]map[string][]int) { + fmt.Println(value) +} + +func main() { + myMap := map[string]map[string][]int{ + "a": {"a2": []int{2, 5, 3}}, + "b": {"bbc": []int{0, 10, 3}}, + "c": {"alex": []int{}}, + } + myFunc(myMap) +} + +// map[a:map[a2:[2 5 3]] b:map[bbc:[0 10 3]] c:map[alex:[]]] diff --git a/part_3/3.3/2.go b/part_3/3.3/2.go new file mode 100644 index 0000000..fc9f2b4 --- /dev/null +++ b/part_3/3.3/2.go @@ -0,0 +1,20 @@ +package main + +import "fmt" + +type MyType map[string]map[string][]int + +func myFunc(value MyType) { + fmt.Println(value) +} + +func main() { + myMap := MyType{ + "a": {"a2": []int{2, 5, 3}}, + "b": {"bbc": []int{0, 10, 3}}, + "c": {"alex": []int{}}, + } + myFunc(myMap) +} + +// map[a:map[a2:[2 5 3]] b:map[bbc:[0 10 3]] c:map[alex:[]]] diff --git a/part_3/3.4/1.go b/part_3/3.4/1.go new file mode 100644 index 0000000..833d901 --- /dev/null +++ b/part_3/3.4/1.go @@ -0,0 +1,19 @@ +package main + +import "fmt" + +var global string = "Global value" + +// global := "Global value" // так объявлять нельзя, будет ошибка + +func myFunc() { + fmt.Println(global) +} + +func main() { + fmt.Println(global) + myFunc() +} + +// Global value +// Global value diff --git a/part_3/3.4/2.go b/part_3/3.4/2.go new file mode 100644 index 0000000..05b97fd --- /dev/null +++ b/part_3/3.4/2.go @@ -0,0 +1,18 @@ +package main + +import "fmt" + +var global string = "Global value" + +func myFunc() { + global := 10 + fmt.Println(global) +} + +func main() { + fmt.Println(global) + myFunc() +} + +// Global value +// 10 diff --git a/part_3/3.4/3.go b/part_3/3.4/3.go new file mode 100644 index 0000000..68ffb54 --- /dev/null +++ b/part_3/3.4/3.go @@ -0,0 +1,20 @@ +package main + +import "fmt" + +var global string = "Global value" + +func myFunc() { + global := 10 + fmt.Println(global) +} + +func main() { + fmt.Println(global) + myFunc() + if true { + local := 20 + fmt.Println(local) + } + local = 5 // undefined: local +} diff --git a/part_3/3.4/4.go b/part_3/3.4/4.go new file mode 100644 index 0000000..fdb4331 --- /dev/null +++ b/part_3/3.4/4.go @@ -0,0 +1,23 @@ +package main + +import "fmt" + +var global string = "Global value" + +func myFunc() { + global := 10 + fmt.Println(global) +} + +func main() { + fmt.Println(global) // Global value + local := 20 + { + fmt.Println(local) // 20 + { + local := 10 + fmt.Println(local) // 10 + } + fmt.Println(local) // 20 + } +} diff --git a/part_3/3.5/1.go b/part_3/3.5/1.go new file mode 100644 index 0000000..1958324 --- /dev/null +++ b/part_3/3.5/1.go @@ -0,0 +1,13 @@ +package main + +import "fmt" + +func add(a, b int) int { + return a + b +} + +func main() { + myFunc := add // var myFunc func(a int, b int) int = add + fmt.Println(add(3, 5)) // 8 + fmt.Println(myFunc(3, 5)) // 8 +} diff --git a/part_3/3.6/1.go b/part_3/3.6/1.go new file mode 100644 index 0000000..9b0fb88 --- /dev/null +++ b/part_3/3.6/1.go @@ -0,0 +1,17 @@ +package main + +import "fmt" + +func add(a, b int) int { + return a + b +} + +func sub(c, a, b int, addFunc func(a int, b int) int) int { + return c - addFunc(a, b) +} + +func main() { + myFunc := add // var myFunc func(a int, b int) int = add + fmt.Println(sub(4, 3, 10, add)) // -9 + fmt.Println(sub(4, 3, 10, myFunc)) // -9 +} diff --git a/part_3/3.6/2.go b/part_3/3.6/2.go new file mode 100644 index 0000000..ba4e8cc --- /dev/null +++ b/part_3/3.6/2.go @@ -0,0 +1,19 @@ +package main + +import "fmt" + +type MyFunctionAdd func(a int, b int) int + +func add(a, b int) int { + return a + b +} + +func sub(c, a, b int, addFunc MyFunctionAdd) int { + return c - addFunc(a, b) +} + +func main() { + myFunc := add // var myFunc func(a int, b int) int = add + fmt.Println(sub(4, 3, 10, add)) // -9 + fmt.Println(sub(4, 3, 10, myFunc)) // -9 +} diff --git a/part_3/3.7/1.go b/part_3/3.7/1.go new file mode 100644 index 0000000..063abbe --- /dev/null +++ b/part_3/3.7/1.go @@ -0,0 +1,20 @@ +package main + +import "fmt" + +type MyFunctionAdd func(a int, b int) int + +func sub(c, a, b int, addFunc MyFunctionAdd) int { + return c - addFunc(a, b) +} + +func main() { + fmt.Println(sub(4, 3, 10, func(a, b int) int { + return a + b + })) // -9 + + myFunc := func(a, b int) int { + return a + b + } + fmt.Println(sub(4, 3, 10, myFunc)) // -9 +} diff --git a/part_3/3.8/1.go b/part_3/3.8/1.go new file mode 100644 index 0000000..5a82e5e --- /dev/null +++ b/part_3/3.8/1.go @@ -0,0 +1,31 @@ +package main + +import "fmt" + +type microwaveCreator func(dish string, model int) string + +var microwaveIndex int = 0 + +func factory(microwaveName string, power int) microwaveCreator { + microwaveIndex++ + model := fmt.Sprintf("%s-RU-001%d", microwaveName, microwaveIndex) + return func(dish string, mode int) string { + str := fmt.Sprintf("Микроволновка %s мощностью %d w Вт,", model, power) + str += fmt.Sprintf("греет блюдо %s в режиме %d", dish, mode) + return str + } +} + +func main() { + microwave := factory("Scarlet", 800) + fmt.Println(microwave("Суп", 3)) + fmt.Println(microwave("Пюре", 2)) + newMicrowave := factory("LG", 1200) + fmt.Println(newMicrowave("Плов", 4)) +} + +/* +Микроволновка Scarlet-RU-0011 мощностью 800 w Вт,греет блюдо Суп в режиме 3 +Микроволновка Scarlet-RU-0011 мощностью 800 w Вт,греет блюдо Пюре в режиме 2 +Микроволновка LG-RU-0012 мощностью 1200 w Вт,греет блюдо Плов в режиме 4 +*/ diff --git a/part_3/3.8/2.go b/part_3/3.8/2.go new file mode 100644 index 0000000..41ec7d1 --- /dev/null +++ b/part_3/3.8/2.go @@ -0,0 +1,23 @@ +package main + +import ( + "fmt" + "math" +) + +type MyPow func(value int) int + +func degree(degree int) MyPow { + return func(value int) int { + return int(math.Pow(float64(value), float64(degree))) + } +} + +func main() { + calculation := degree(3) + fmt.Println(calculation(3)) // 27 + fmt.Println(calculation(4)) // 64 + calculation = degree(9) + fmt.Println(calculation(4)) // 262144 + fmt.Println(calculation(7)) // 40353607 +} diff --git a/part_3/3.9/1.go b/part_3/3.9/1.go new file mode 100644 index 0000000..dca5369 --- /dev/null +++ b/part_3/3.9/1.go @@ -0,0 +1,16 @@ +package main + +import "fmt" + +func sumElem(slice []int) int { + fmt.Println(slice) + if len(slice) <= 1 { + return slice[0] + } + return slice[0] + sumElem(slice[1:]) +} + +func main() { + mySlice := []int{2, 5, 22, 9, 0} + fmt.Println(sumElem(mySlice)) +} diff --git a/part_3/3.9/2.go b/part_3/3.9/2.go new file mode 100644 index 0000000..5238ff4 --- /dev/null +++ b/part_3/3.9/2.go @@ -0,0 +1,20 @@ +package main + +import "fmt" + +func sumElem(slice []int) int { + fmt.Println(slice) + if len(slice) <= 1 { + return slice[0] + } + return anotherFunction(slice) +} + +func anotherFunction(slice []int) int { + return slice[0] + sumElem(slice[1:]) +} + +func main() { + mySlice := []int{2, 5, 22, 9, 0} + fmt.Println(sumElem(mySlice)) +} diff --git a/part_4/4.1-4.2/golang/first/go.mod b/part_4/4.1-4.2/golang/first/go.mod new file mode 100644 index 0000000..2809355 --- /dev/null +++ b/part_4/4.1-4.2/golang/first/go.mod @@ -0,0 +1,5 @@ +module golang/first + +go 1.24 + +require github.com/google/uuid v1.6.0 // indirect diff --git a/part_4/4.1-4.2/golang/first/go.sum b/part_4/4.1-4.2/golang/first/go.sum new file mode 100644 index 0000000..7790d7c --- /dev/null +++ b/part_4/4.1-4.2/golang/first/go.sum @@ -0,0 +1,2 @@ +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= diff --git a/part_4/4.1-4.2/golang/first/main.go b/part_4/4.1-4.2/golang/first/main.go new file mode 100644 index 0000000..7144bb9 --- /dev/null +++ b/part_4/4.1-4.2/golang/first/main.go @@ -0,0 +1,12 @@ +package main + +import ( + "fmt" + + "github.com/google/uuid" +) + +func main() { + myUUID := uuid.New() + fmt.Println(myUUID) +} diff --git a/part_4/4.6/golang/first/go.mod b/part_4/4.6/golang/first/go.mod new file mode 100644 index 0000000..2809355 --- /dev/null +++ b/part_4/4.6/golang/first/go.mod @@ -0,0 +1,5 @@ +module golang/first + +go 1.24 + +require github.com/google/uuid v1.6.0 // indirect diff --git a/part_4/4.6/golang/first/go.sum b/part_4/4.6/golang/first/go.sum new file mode 100644 index 0000000..7790d7c --- /dev/null +++ b/part_4/4.6/golang/first/go.sum @@ -0,0 +1,2 @@ +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= diff --git a/part_4/4.6/golang/first/main.go b/part_4/4.6/golang/first/main.go new file mode 100644 index 0000000..2d4ae13 --- /dev/null +++ b/part_4/4.6/golang/first/main.go @@ -0,0 +1,19 @@ +package main + +import ( + "fmt" + "golang/first/utils" + + "github.com/google/uuid" +) + +func main() { + firstUUID := uuid.New() + fmt.Println(firstUUID) // 791e0d38-c0ad-4241-9918-4ac507d92135 + fmt.Println(utils.ReplaceSymbols(firstUUID, "-", "")) // 791e0d38c0ad424199184ac507d92135 + secondUUID := uuid.New() + fmt.Println(utils.MergeUUID(firstUUID, secondUUID)) + // 791e0d38-c0ad-4241-9918-4ac507d9213523acd18c-4659-45b4-ba8d-c47d895155e5 + fmt.Println(utils.Contains(firstUUID, "e")) // true + fmt.Println(utils.Contains(secondUUID, "e")) // true +} diff --git a/part_4/4.6/golang/first/utils/uuid_convertor.go b/part_4/4.6/golang/first/utils/uuid_convertor.go new file mode 100644 index 0000000..6309621 --- /dev/null +++ b/part_4/4.6/golang/first/utils/uuid_convertor.go @@ -0,0 +1,19 @@ +package utils + +import ( + "strings" + + "github.com/google/uuid" +) + +func ReplaceSymbols(oldUUID uuid.UUID, old, new string) string { + return strings.ReplaceAll(oldUUID.String(), old, new) +} + +func MergeUUID(first, second uuid.UUID) string { + return first.String() + second.String() +} + +func Contains(uuid uuid.UUID, symbol string) bool { + return strings.ContainsAny(uuid.String(), symbol) +} diff --git a/part_4/4.7/golang/first/another_package/mypack.go b/part_4/4.7/golang/first/another_package/mypack.go new file mode 100644 index 0000000..725c381 --- /dev/null +++ b/part_4/4.7/golang/first/another_package/mypack.go @@ -0,0 +1,5 @@ +package mypack + +func Add(a, b int) int { + return a + b +} diff --git a/part_4/4.7/golang/first/go.mod b/part_4/4.7/golang/first/go.mod new file mode 100644 index 0000000..2809355 --- /dev/null +++ b/part_4/4.7/golang/first/go.mod @@ -0,0 +1,5 @@ +module golang/first + +go 1.24 + +require github.com/google/uuid v1.6.0 // indirect diff --git a/part_4/4.7/golang/first/go.sum b/part_4/4.7/golang/first/go.sum new file mode 100644 index 0000000..7790d7c --- /dev/null +++ b/part_4/4.7/golang/first/go.sum @@ -0,0 +1,2 @@ +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= diff --git a/part_4/4.7/golang/first/main.go b/part_4/4.7/golang/first/main.go new file mode 100644 index 0000000..418932a --- /dev/null +++ b/part_4/4.7/golang/first/main.go @@ -0,0 +1,15 @@ +package main + +import ( + f "fmt" + pack "golang/first/another_package" + u "golang/first/utils" + + id "github.com/google/uuid" +) + +func main() { + firstUUID := id.New() + f.Println(u.ReplaceSymbols(firstUUID, "-", "")) // 45f09a89584b4f66936cf3368e3f634b + print(pack.Add(4, 7)) // 11 +} diff --git a/part_4/4.7/golang/first/utils/uuid_convertor.go b/part_4/4.7/golang/first/utils/uuid_convertor.go new file mode 100644 index 0000000..6309621 --- /dev/null +++ b/part_4/4.7/golang/first/utils/uuid_convertor.go @@ -0,0 +1,19 @@ +package utils + +import ( + "strings" + + "github.com/google/uuid" +) + +func ReplaceSymbols(oldUUID uuid.UUID, old, new string) string { + return strings.ReplaceAll(oldUUID.String(), old, new) +} + +func MergeUUID(first, second uuid.UUID) string { + return first.String() + second.String() +} + +func Contains(uuid uuid.UUID, symbol string) bool { + return strings.ContainsAny(uuid.String(), symbol) +} diff --git a/part_4/4.8/golang/first/another_package/mypack.go b/part_4/4.8/golang/first/another_package/mypack.go new file mode 100644 index 0000000..725c381 --- /dev/null +++ b/part_4/4.8/golang/first/another_package/mypack.go @@ -0,0 +1,5 @@ +package mypack + +func Add(a, b int) int { + return a + b +} diff --git a/part_4/4.8/golang/first/go.mod b/part_4/4.8/golang/first/go.mod new file mode 100644 index 0000000..e734a3f --- /dev/null +++ b/part_4/4.8/golang/first/go.mod @@ -0,0 +1,9 @@ +module golang/first + +go 1.24 + +replace golang/second => ../second // путь, относительно текущей директории проекта + +require golang/second v0.0.0-00010101000000-000000000000 + +require github.com/google/uuid v1.6.0 // indirect diff --git a/part_4/4.8/golang/first/go.sum b/part_4/4.8/golang/first/go.sum new file mode 100644 index 0000000..7790d7c --- /dev/null +++ b/part_4/4.8/golang/first/go.sum @@ -0,0 +1,2 @@ +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= diff --git a/part_4/4.8/golang/first/main.go b/part_4/4.8/golang/first/main.go new file mode 100644 index 0000000..257830c --- /dev/null +++ b/part_4/4.8/golang/first/main.go @@ -0,0 +1,19 @@ +package main + +import ( + f "fmt" + pack "golang/first/another_package" + u "golang/first/utils" + + "golang/second" + + id "github.com/google/uuid" +) + +func main() { + firstUUID := id.New() + f.Println(u.ReplaceSymbols(firstUUID, "-", "")) // 8912acef6d3d40aa94f21333faa1c679 + f.Println(pack.Add(4, 7)) // 11 + f.Println(second.AddInt(3, 5)) // 8 + f.Println(second.DivFloat(54.48, 3.66)) // 14.885245901639342 +} diff --git a/part_4/4.8/golang/first/utils/uuid_convertor.go b/part_4/4.8/golang/first/utils/uuid_convertor.go new file mode 100644 index 0000000..6309621 --- /dev/null +++ b/part_4/4.8/golang/first/utils/uuid_convertor.go @@ -0,0 +1,19 @@ +package utils + +import ( + "strings" + + "github.com/google/uuid" +) + +func ReplaceSymbols(oldUUID uuid.UUID, old, new string) string { + return strings.ReplaceAll(oldUUID.String(), old, new) +} + +func MergeUUID(first, second uuid.UUID) string { + return first.String() + second.String() +} + +func Contains(uuid uuid.UUID, symbol string) bool { + return strings.ContainsAny(uuid.String(), symbol) +} diff --git a/part_4/4.8/golang/second/float.go b/part_4/4.8/golang/second/float.go new file mode 100644 index 0000000..88a7f50 --- /dev/null +++ b/part_4/4.8/golang/second/float.go @@ -0,0 +1,17 @@ +package second + +func AddFloat(a, b float64) float64 { + return a + b +} + +func SubFloat(a, b float64) float64 { + return a - b +} + +func MulFloat(a, b float64) float64 { + return a * b +} + +func DivFloat(a, b float64) float64 { + return a / b +} diff --git a/part_4/4.8/golang/second/go.mod b/part_4/4.8/golang/second/go.mod new file mode 100644 index 0000000..4ec8871 --- /dev/null +++ b/part_4/4.8/golang/second/go.mod @@ -0,0 +1,3 @@ +module golang/second + +go 1.24 diff --git a/part_4/4.8/golang/second/integer.go b/part_4/4.8/golang/second/integer.go new file mode 100644 index 0000000..667e320 --- /dev/null +++ b/part_4/4.8/golang/second/integer.go @@ -0,0 +1,17 @@ +package second + +func AddInt(a, b int) int { + return a + b +} + +func SubInt(a, b int) int { + return a - b +} + +func MulInt(a, b int) int { + return a * b +} + +func DivInt(a, b int) int { + return a / b +} diff --git a/part_5/5.1/1.go b/part_5/5.1/1.go new file mode 100644 index 0000000..6956f14 --- /dev/null +++ b/part_5/5.1/1.go @@ -0,0 +1,16 @@ +package main + +import "fmt" + +type employee struct { + name string + departmentName string + age uint8 + position string +} + +func main() { + var emp employee + emp2 := employee{} + fmt.Println(emp, emp2) // { 0 } { 0 } +} diff --git a/part_5/5.1/10.go b/part_5/5.1/10.go new file mode 100644 index 0000000..7101a06 --- /dev/null +++ b/part_5/5.1/10.go @@ -0,0 +1,21 @@ +package main + +import "fmt" + +type point struct { + x int + y int +} + +type shape struct { + name string + center point +} + +func main() { + myShape := shape{ + name: "Cube", + center: point{x: 10, y: 6}, + } + fmt.Printf("%+v\n", myShape) // {name:Cube center:{x:10 y:6}} +} diff --git a/part_5/5.1/2.go b/part_5/5.1/2.go new file mode 100644 index 0000000..c842986 --- /dev/null +++ b/part_5/5.1/2.go @@ -0,0 +1,29 @@ +package main + +import "fmt" + +type employee struct { + name string + departmentName string + age uint8 + position string +} + +func main() { + emp1 := employee{ + name: "Alex", + age: 25, + departmentName: "R&D", + position: "Assistant", + } + emp2 := employee{ + name: "Tom", + position: "Intern", + } + emp3 := employee{"Alex", "R&D", 25, "Assistant"} // ok + // emp3 := employee{"Alex", "R&D"} – ошибка!!! + + fmt.Println(emp1) // {Alex R&D 25 Assistant} + fmt.Println(emp2) // {Tom 0 Intern} + fmt.Println(emp3) // {Alex R&D 25 Assistant} +} diff --git a/part_5/5.1/3.go b/part_5/5.1/3.go new file mode 100644 index 0000000..ef8f21a --- /dev/null +++ b/part_5/5.1/3.go @@ -0,0 +1,22 @@ +package main + +import "fmt" + +type employee struct { + name string + departmentName string + age uint8 + position string +} + +func main() { + emp2 := employee{ + name: "Tom", + position: "Intern", + } + emp2.age = 22 + emp2.departmentName = "R&D" + fmt.Println(emp2) // {Tom R&D 22 Intern} + emp2.position = "Engineer" + fmt.Println(emp2) // {Tom R&D 22 Engineer} +} diff --git a/part_5/5.1/4.go b/part_5/5.1/4.go new file mode 100644 index 0000000..870544e --- /dev/null +++ b/part_5/5.1/4.go @@ -0,0 +1,22 @@ +package main + +import "fmt" + +type employee struct { + name string + departmentName string + age uint8 + position string +} + +func main() { + emp2 := employee{ + name: "Tom", + position: "Intern", + } + emp2.age = 22 + emp2.departmentName = "R&D" + fmt.Printf("%+v\n", emp2) // {name:Tom departmentName:R&D age:22 position:Intern} + emp2.position = "Engineer" + fmt.Printf("%+v\n", emp2) // {name:Tom departmentName:R&D age:22 position:Engineer} +} diff --git a/part_5/5.1/5.1.7/golang/factory/go.mod b/part_5/5.1/5.1.7/golang/factory/go.mod new file mode 100644 index 0000000..744a3fb --- /dev/null +++ b/part_5/5.1/5.1.7/golang/factory/go.mod @@ -0,0 +1,3 @@ +module golang/factory + +go 1.24 diff --git a/part_5/5.1/5.1.7/golang/factory/main.go b/part_5/5.1/5.1.7/golang/factory/main.go new file mode 100644 index 0000000..9a3ea95 --- /dev/null +++ b/part_5/5.1/5.1.7/golang/factory/main.go @@ -0,0 +1,22 @@ +package main + +import ( + "fmt" + "golang/factory/shape" +) + +func main() { + + myShape := shape.Shape{ + Name: "Cube", + Center: shape.Point{X: 4, Y: 5}, + } + + myShape1 := shape.Shape{"Triangle", shape.Point{1, 9}} + + fmt.Printf("%+v\n", myShape) // {Name:Cube Center:{X:4 Y:5}} + fmt.Printf("%+v\n", myShape1) // {Name:Triangle Center:{X:1 Y:9}} + myShape.Center.Y = 2 + myShape.Name = "Circle" + fmt.Printf("%+v\n", myShape) // {Name:Circle Center:{X:4 Y:2}} +} diff --git a/part_5/5.1/5.1.7/golang/factory/shape/shape.go b/part_5/5.1/5.1.7/golang/factory/shape/shape.go new file mode 100644 index 0000000..ba0e6f3 --- /dev/null +++ b/part_5/5.1/5.1.7/golang/factory/shape/shape.go @@ -0,0 +1,11 @@ +package shape + +type Point struct { + X int + Y int +} + +type Shape struct { + Name string + Center Point +} diff --git a/part_5/5.1/5.go b/part_5/5.1/5.go new file mode 100644 index 0000000..5b1e1fc --- /dev/null +++ b/part_5/5.1/5.go @@ -0,0 +1,22 @@ +package main + +import "fmt" + +type employee struct { + name string + departmentName string + age uint8 + position string +} + +func main() { + emp2 := employee{ + name: "Tom", + position: "Intern", + } + emp2.age = 22 + emp2.departmentName = "R&D" + fmt.Printf("%+v\n", emp2.age) // 22 + employeeAge := emp2.age + fmt.Println(employeeAge) // 22 +} diff --git a/part_5/5.1/6.go b/part_5/5.1/6.go new file mode 100644 index 0000000..7253df4 --- /dev/null +++ b/part_5/5.1/6.go @@ -0,0 +1,38 @@ +package main + +import "fmt" + +type employee struct { + name string + departmentName string + age uint8 + position string +} + +func main() { + emp2 := employee{ + name: "Tom", + position: "Intern", + } + empPoint := &emp2 // первый способ через оператор & + empPoint1 := &employee{ // второй способ через оператор & + name: "Maxim", + position: "Intern", + age: 18, + } + // изменение значений полей через указатель на структуру + (*empPoint).departmentName = "R&D" + // тоже самое, что + empPoint.age = 23 + empPoint1.departmentName = "R&D" + fmt.Printf("%+v\n", *empPoint) // {name:Tom departmentName:R&D age:23 position:Intern} + fmt.Printf("%+v\n", *empPoint1) // {name:Maxim departmentName:R&D age:18 position:Intern} + + empPoint2 := new(employee) // использование ключевого слова new + fmt.Printf("%+v\n", *empPoint2) // {name: departmentName: age:0 position:} + empPoint2.departmentName = "Oo" + empPoint2.name = "Alex" + empPoint2.position = "Engineer" + empPoint2.age = 40 + fmt.Printf("%+v\n", *empPoint2) // {name:Alex departmentName:Oo age:40 position:Engineer} +} diff --git a/part_5/5.1/7.go b/part_5/5.1/7.go new file mode 100644 index 0000000..531b645 --- /dev/null +++ b/part_5/5.1/7.go @@ -0,0 +1,29 @@ +package main + +import "fmt" + +type employee struct { + name string + string // первое анонимное поле + uint8 // второе анонимное поле + position string +} + +func main() { + emp := employee{ + name: "Tom", + position: "Intern", + } + emp1 := employee{ + name: "Alex", + position: "Intern", + uint8: 17, + string: "R&D", + } + // присваиваем значение анонимному полю + emp.uint8 = 22 + emp.string = "R&D" + fmt.Printf("%+v\n", emp1) //{name:Alex string:R&D uint8:17 position:Intern} + fmt.Printf("%+v\n", emp) // {name:Tom string:R&D uint8:22 position:Intern} + fmt.Printf("%+v\n", emp.uint8) // 22 - вывод значения анонимного поля +} diff --git a/part_5/5.1/8.go b/part_5/5.1/8.go new file mode 100644 index 0000000..2c16d8a --- /dev/null +++ b/part_5/5.1/8.go @@ -0,0 +1,34 @@ +package main + +import "fmt" + +type employee struct { + name string + age uint8 +} + +func valueFunc(emp employee) { + emp.name = "O_O" + fmt.Printf("Copy value: %+v\n", emp) +} + +func pointFunc(emp *employee) { + emp.name = "^_^" + fmt.Printf("Point to value: %+v\n", emp) +} + +func main() { + emp := employee{ + name: "Tom", + age: 45, + } + newEmployee := emp + newEmployee.age = 22 + fmt.Printf("newEmployee = %+v\n", newEmployee) + fmt.Printf("emp = %+v\n", emp) + + valueFunc(emp) // передача в функцию по значению + fmt.Printf("emp = %+v\n", emp) + pointFunc(&emp) // передача в функцию по указателю + fmt.Printf("emp = %+v\n", emp) +} diff --git a/part_5/5.1/9.go b/part_5/5.1/9.go new file mode 100644 index 0000000..49f6eef --- /dev/null +++ b/part_5/5.1/9.go @@ -0,0 +1,20 @@ +package main + +import "fmt" + +type point struct { + x int + y int +} + +func checkOutput(first, second int, check bool) { + fmt.Printf("point%d == point%d - %t\n", first, second, check) +} + +func main() { + point1 := point{10, 20} + point2 := point{10, 20} + point3 := point{x: 2, y: 43} + checkOutput(1, 2, point1 == point2) + checkOutput(2, 3, point2 == point3) +} diff --git a/part_5/5.10/1.go b/part_5/5.10/1.go new file mode 100644 index 0000000..85957aa --- /dev/null +++ b/part_5/5.10/1.go @@ -0,0 +1,21 @@ +package main + +import "fmt" + +func SumInt(a, b int) int { + return a + b +} + +func SumFloat(a, b float64) float64 { + return a + b +} + +func SumString(a, b string) string { + return a + b +} + +func main() { + fmt.Println(SumFloat(10.3, 45.1)) // 55.4 + fmt.Println(SumInt(10, 45)) // 55 + fmt.Println(SumString("^_", "^")) // ^_^ +} diff --git a/part_5/5.10/10.go b/part_5/5.10/10.go new file mode 100644 index 0000000..46bd07c --- /dev/null +++ b/part_5/5.10/10.go @@ -0,0 +1,24 @@ +package main + +import "fmt" + +func CreateNewMap[K comparable, V any](k []K, v *[]V) *map[K]V { + // создание словаря из среза и указателя на срез + newMap := make(map[K]V) + if len(k) < len(*v) { + for idx, elem := range k { + newMap[elem] = (*v)[idx] + } + } else { + for idx, elem := range *v { + newMap[k[idx]] = elem + } + } + return &newMap +} + +func main() { + intSlice := []int{1, 3, 4, 6, 7} + stringSlice := []string{"Oo", "^_^", "-_-"} + fmt.Println(CreateNewMap(intSlice, &stringSlice)) // &map[1:Oo 3:^_^ 4:-_-] +} diff --git a/part_5/5.10/2.go b/part_5/5.10/2.go new file mode 100644 index 0000000..af8f917 --- /dev/null +++ b/part_5/5.10/2.go @@ -0,0 +1,13 @@ +package main + +import "fmt" + +func Sum[T int | float64 | string](a, b T) T { + return a + b +} + +func main() { + fmt.Println(Sum(10.3, 45.1)) // 55.4 + fmt.Println(Sum(10, 45)) // 55 + fmt.Println(Sum("^_", "^")) // ^_^ +} diff --git a/part_5/5.10/3.go b/part_5/5.10/3.go new file mode 100644 index 0000000..1f614ee --- /dev/null +++ b/part_5/5.10/3.go @@ -0,0 +1,16 @@ +package main + +import "fmt" + +type MyInt int + +func Sum[T int | float64 | string](a, b T) T { + return a + b +} + +func main() { + var value1, value2 MyInt = 34, 22 + fmt.Println(Sum(value1, value2)) + // MyInt does not implement int|float64|string + // (possibly missing ~ for int in constraint int|float64|string) +} diff --git a/part_5/5.10/4.go b/part_5/5.10/4.go new file mode 100644 index 0000000..2535b5c --- /dev/null +++ b/part_5/5.10/4.go @@ -0,0 +1,14 @@ +package main + +import "fmt" + +type MyInt int + +func Sum[T ~int | float64 | string](a, b T) T { + return a + b +} + +func main() { + var value1, value2 MyInt = 34, 22 + fmt.Println(Sum(value1, value2)) // 56 +} diff --git a/part_5/5.10/5.go b/part_5/5.10/5.go new file mode 100644 index 0000000..e058391 --- /dev/null +++ b/part_5/5.10/5.go @@ -0,0 +1,17 @@ +package main + +import "fmt" + +type MyInt int + +func Sum[T ~int | float64 | string](a, b T) T { + return a + b +} + +func main() { + var value1, value2 MyInt = 34, 22 + fmt.Println(Sum[MyInt](value1, value2)) // 56 + fmt.Println(Sum[float64](10.3, 45.1)) // 55.4 + fmt.Println(Sum[int](10, 45)) // 55 + fmt.Println(Sum[string]("^_", "^")) // ^_^ +} diff --git a/part_5/5.10/6.go b/part_5/5.10/6.go new file mode 100644 index 0000000..efefbb0 --- /dev/null +++ b/part_5/5.10/6.go @@ -0,0 +1,21 @@ +package main + +import "fmt" + +type MyInt int + +type MyInterface interface { + ~int | float64 | string | uint16 | uint32 +} + +func Sum[T MyInterface](a, b T) T { + return a + b +} + +func main() { + var value1, value2 MyInt = 34, 22 + fmt.Println(Sum(value1, value2)) // 56 + fmt.Println(Sum(10.3, 45.1)) // 55.4 + fmt.Println(Sum(10, 45)) // 55 + fmt.Println(Sum("^_", "^")) // ^_^ +} diff --git a/part_5/5.10/7.go b/part_5/5.10/7.go new file mode 100644 index 0000000..69533c1 --- /dev/null +++ b/part_5/5.10/7.go @@ -0,0 +1,28 @@ +package main + +import "fmt" + +func reverseSlice[T any](slice []T) []T { + length := len(slice) + newSlice := make([]T, length) + + for i, elem := range slice { + newSlice[length-i-1] = elem + } + return newSlice +} + +func printMySlice[T any](slice []T) { + fmt.Printf("Slice values before reverse: %v\n", slice) + fmt.Printf("Slice values after reverse: %v\n", reverseSlice(slice)) + fmt.Println() +} + +func main() { + intSlice := []int{1, 3, 4, 6, 7} + floatSlice := []float64{3.12, 45.6, 21.6, 5.11} + stringSlice := []string{"Oo", "^_^", "-_-"} + printMySlice(intSlice) + printMySlice(floatSlice) + printMySlice(stringSlice) +} diff --git a/part_5/5.10/8.go b/part_5/5.10/8.go new file mode 100644 index 0000000..7ae77a4 --- /dev/null +++ b/part_5/5.10/8.go @@ -0,0 +1,53 @@ +package main + +import "fmt" + +func GetMapValues[K comparable, V any](m map[K]V) []V { + // вернет срез из значений словаря + values := make([]V, len(m)) + idx := 0 + for _, v := range m { + values[idx] = v + idx++ + } + return values +} + +func GetMapKeys[K comparable, V any](m map[K]V) []K { + // вернет срез из ключей словаря + keys := make([]K, len(m)) + idx := 0 + for k, _ := range m { + keys[idx] = k + idx++ + } + return keys +} + +func CreateNewMap[K comparable, V any](k []K, v []V) map[K]V { + // создание словаря из двух срезов + newMap := make(map[K]V) + if len(k) < len(v) { + for idx, elem := range k { + newMap[elem] = v[idx] + } + } else { + for idx, elem := range v { + newMap[k[idx]] = elem + } + } + return newMap +} + +func main() { + intSlice := []int{1, 3, 4, 6, 7} + stringSlice := []string{"Oo", "^_^", "-_-"} + myMap := map[int]string{ + 1: "Alex", + 2: "Maxim", + 200: "Jon", + } + fmt.Println(GetMapKeys(myMap)) // [1 2 200] + fmt.Println(GetMapValues(myMap)) // [Alex Maxim Jon] + fmt.Println(CreateNewMap(intSlice, stringSlice)) // map[1:Oo 3:^_^ 4:-_-] +} diff --git a/part_5/5.10/9.go b/part_5/5.10/9.go new file mode 100644 index 0000000..4d5c0a1 --- /dev/null +++ b/part_5/5.10/9.go @@ -0,0 +1,38 @@ +package main + +import "fmt" + +type MyStruct[K string | uint, T string | []string] struct { + id K + data T +} + +func (m *MyStruct[K, T]) getID() K { + return m.id +} + +func (m *MyStruct[K, T]) getData() T { + return m.data +} + +func (m *MyStruct[K, T]) setData(data T) { + m.data = data +} + +func main() { + myStruct := MyStruct[uint, string]{ + id: 1, + data: "Oo", + } + fmt.Printf("K = int, T = string: %+v\n", myStruct) + myStruct.setData("^_^") + fmt.Printf("K = int, T = string: %+v\n", myStruct) + + newStruct := MyStruct[string, []string]{ + id: "0xA321", + data: []string{"10", "20", "30"}, + } + fmt.Printf("K = string, T = []string: %+v\n", newStruct) + newStruct.setData([]string{}) + fmt.Printf("K = string, T = []string: %+v\n", newStruct) +} diff --git a/part_5/5.2/1.go b/part_5/5.2/1.go new file mode 100644 index 0000000..71b174d --- /dev/null +++ b/part_5/5.2/1.go @@ -0,0 +1,24 @@ +package main + +import "fmt" + +type RUB uint // пользовательский именованный тип RUB + +const RUB2USD uint = 61 +const RUB2EUR uint = 65 + +//связываем тип RUB с методом конвертации рублей в доллары +func (r RUB) convertRUB2USD() uint { + return uint(r) / RUB2USD +} + +//связываем тип RUB с методом конвертации рублей в евро +func (r RUB) convertRUB2EUR() uint { + return uint(r) / RUB2EUR +} + +func main() { + var rub RUB = 3475 + fmt.Printf("%d рублей примерно = %d долларов\n", rub, rub.convertRUB2USD()) + fmt.Printf("%d рублей примерно = %d евро\n", rub, rub.convertRUB2EUR()) +} diff --git a/part_5/5.2/2.go b/part_5/5.2/2.go new file mode 100644 index 0000000..46e03a6 --- /dev/null +++ b/part_5/5.2/2.go @@ -0,0 +1,29 @@ +package main + +import "fmt" + +type RUB uint // пользовательский именованный тип RUB + +const RUB2USD uint = 61 +const RUB2EUR uint = 65 + +//связываем тип RUB с методом конвертации рублей в доллары +func (r RUB) convertRUB2USD() uint { + return uint(r) / RUB2USD +} + +//связываем тип RUB с методом конвертации рублей в евро +func (r RUB) convertRUB2EUR() uint { + return uint(r) / RUB2EUR +} + +func (r RUB) setNewValue(rub RUB) { + r = rub + fmt.Printf("В кошельке теперь %d рублей\n", r) +} + +func main() { + var rub RUB = 3475 + rub.setNewValue(9000) + fmt.Printf("В кошельке на самом деле %d рублей\n", rub) +} diff --git a/part_5/5.2/3.go b/part_5/5.2/3.go new file mode 100644 index 0000000..6d341a5 --- /dev/null +++ b/part_5/5.2/3.go @@ -0,0 +1,29 @@ +package main + +import "fmt" + +type RUB uint // пользовательский именованный тип RUB + +const RUB2USD uint = 61 +const RUB2EUR uint = 65 + +//связываем тип RUB с методом конвертации рублей в доллары +func (r RUB) convertRUB2USD() uint { + return uint(r) / RUB2USD +} + +//связываем тип RUB с методом конвертации рублей в евро +func (r RUB) convertRUB2EUR() uint { + return uint(r) / RUB2EUR +} + +func (r *RUB) setNewValue(rub RUB) { + *r = rub + fmt.Printf("В кошельке теперь %d рублей\n", *r) +} + +func main() { + var rub RUB = 3475 + rub.setNewValue(9000) + fmt.Printf("В кошельке на самом деле %d рублей\n", rub) +} diff --git a/part_5/5.3/golang/factory/go.mod b/part_5/5.3/golang/factory/go.mod new file mode 100644 index 0000000..744a3fb --- /dev/null +++ b/part_5/5.3/golang/factory/go.mod @@ -0,0 +1,3 @@ +module golang/factory + +go 1.24 diff --git a/part_5/5.3/golang/factory/main.go b/part_5/5.3/golang/factory/main.go new file mode 100644 index 0000000..ba39467 --- /dev/null +++ b/part_5/5.3/golang/factory/main.go @@ -0,0 +1,19 @@ +package main + +import ( + "fmt" + "golang/factory/shape" +) + +func main() { + + myShape := shape.Shape{ + Name: "Cube", + Center: shape.Point{X: 4, Y: 5}, + } + + fmt.Printf("%+v\n", myShape) // {Name:Cube Center:{X:4 Y:5} color:} + myShape.SetColor("Gold") + fmt.Printf("%+v\n", myShape) // {Name:Cube Center:{X:4 Y:5} color:Gold} + fmt.Printf("Shape color: %v\n", myShape.GetColor()) // Shape color: Gold +} diff --git a/part_5/5.3/golang/factory/shape/shape.go b/part_5/5.3/golang/factory/shape/shape.go new file mode 100644 index 0000000..97220c7 --- /dev/null +++ b/part_5/5.3/golang/factory/shape/shape.go @@ -0,0 +1,20 @@ +package shape + +type Point struct { + X int + Y int +} + +type Shape struct { + Name string + Center Point + color string +} + +func (s *Shape) SetColor(color string) { + s.color = color +} + +func (s *Shape) GetColor() string { + return s.color +} diff --git a/part_5/5.4/golang/factory/go.mod b/part_5/5.4/golang/factory/go.mod new file mode 100644 index 0000000..744a3fb --- /dev/null +++ b/part_5/5.4/golang/factory/go.mod @@ -0,0 +1,3 @@ +module golang/factory + +go 1.24 diff --git a/part_5/5.4/golang/factory/main.go b/part_5/5.4/golang/factory/main.go new file mode 100644 index 0000000..ad765c5 --- /dev/null +++ b/part_5/5.4/golang/factory/main.go @@ -0,0 +1,13 @@ +package main + +import ( + "fmt" + "golang/factory/shape" +) + +func main() { + myShape1 := shape.NewShape("Cube", "Gold", 4, 5) + myShape2 := shape.NewShapeWithPoint("Circle", "Green", shape.Point{X: 5, Y: 7}) + fmt.Printf("%+v\n", myShape1) // {Name:Cube Center:{X:4 Y:5} color:Gold} + fmt.Printf("%+v\n", *myShape2) // {Name:Circle Center:{X:5 Y:7} color:Green} +} diff --git a/part_5/5.4/golang/factory/shape/shape.go b/part_5/5.4/golang/factory/shape/shape.go new file mode 100644 index 0000000..57201a2 --- /dev/null +++ b/part_5/5.4/golang/factory/shape/shape.go @@ -0,0 +1,36 @@ +package shape + +type Point struct { + X int + Y int +} + +type Shape struct { + Name string + Center Point + color string +} + +func (s *Shape) SetColor(color string) { + s.color = color +} + +func (s *Shape) GetColor() string { + return s.color +} + +func NewShape(name, color string, x, y int) Shape { + return Shape{ + Name: name, + color: color, + Center: Point{X: x, Y: y}, + } +} + +func NewShapeWithPoint(name, color string, center Point) *Shape { + return &Shape{ + Name: name, + color: color, + Center: center, + } +} diff --git a/part_5/5.6/golang/factory/go.mod b/part_5/5.6/golang/factory/go.mod new file mode 100644 index 0000000..744a3fb --- /dev/null +++ b/part_5/5.6/golang/factory/go.mod @@ -0,0 +1,3 @@ +module golang/factory + +go 1.24 diff --git a/part_5/5.6/golang/factory/main.go b/part_5/5.6/golang/factory/main.go new file mode 100644 index 0000000..8e9aa85 --- /dev/null +++ b/part_5/5.6/golang/factory/main.go @@ -0,0 +1,24 @@ +package main + +import ( + "fmt" + "golang/factory/shape" +) + +func main() { + rectangle := shape.NewRectangle(10, 6, shape.Point{X: 6, Y: -8}, "Gold") + + fmt.Printf("%+v\n", *rectangle) + fmt.Printf("%+v\n", rectangle.GetName()) + fmt.Printf("Perimeter = %+v\n", rectangle.GetPerimeter()) + fmt.Printf("Area = %+v\n", rectangle.GetArea()) + + // меняем значения полей + rectangle.SetLength(15) + rectangle.SetWidth(7) + rectangle.SetColor("Green") + + fmt.Printf("%+v\n", *rectangle) + fmt.Printf("New perimeter = %+v\n", rectangle.GetPerimeter()) + fmt.Printf("New Area = %+v\n", rectangle.GetArea()) +} diff --git a/part_5/5.6/golang/factory/shape/rectangle.go b/part_5/5.6/golang/factory/shape/rectangle.go new file mode 100644 index 0000000..b2b4aee --- /dev/null +++ b/part_5/5.6/golang/factory/shape/rectangle.go @@ -0,0 +1,47 @@ +package shape + +type Rectangle struct { + shape // композиция + width uint + length uint +} + +func (r *Rectangle) GetWidth() uint { + return r.width +} + +func (r *Rectangle) GetLength() uint { + return r.length +} + +func (r *Rectangle) SetWidth(width uint) { + r.width = width +} + +func (r *Rectangle) SetLength(length uint) { + r.length = length +} + +func (r *Rectangle) GetPerimeter() uint { + return (r.length + r.width) * 2 +} + +func (r *Rectangle) GetArea() uint { + return r.length * r.width +} + +func (r *Rectangle) GetName() string { + return "Super-puper " + r.shape.GetName() +} + +func NewRectangle(width, length uint, center Point, color string) *Rectangle { + return &Rectangle{ + shape: shape{ + name: "Rectangle", + color: color, + center: center, + }, + width: width, + length: length, + } +} diff --git a/part_5/5.6/golang/factory/shape/shape.go b/part_5/5.6/golang/factory/shape/shape.go new file mode 100644 index 0000000..abf361b --- /dev/null +++ b/part_5/5.6/golang/factory/shape/shape.go @@ -0,0 +1,32 @@ +package shape + +type Point struct { + X int + Y int +} + +type shape struct { + name string + center Point + color string +} + +func (s *shape) SetColor(color string) { + s.color = color +} + +func (s *shape) GetColor() string { + return s.color +} + +func (s *shape) GetName() string { + return s.name +} + +func (s *shape) MoveCenter(point Point) { + s.center = point +} + +func (s *shape) GetCenter() Point { + return s.center +} diff --git a/part_5/5.7/golang/factory/go.mod b/part_5/5.7/golang/factory/go.mod new file mode 100644 index 0000000..744a3fb --- /dev/null +++ b/part_5/5.7/golang/factory/go.mod @@ -0,0 +1,3 @@ +module golang/factory + +go 1.24 diff --git a/part_5/5.7/golang/factory/main.go b/part_5/5.7/golang/factory/main.go new file mode 100644 index 0000000..056c82c --- /dev/null +++ b/part_5/5.7/golang/factory/main.go @@ -0,0 +1,85 @@ +package main + +import ( + "fmt" + "golang/factory/shape" +) + +func printShapeName(name shape.IShapeName) { + fmt.Printf("IShapeName: %v\n", name.GetName()) +} + +func getIShapeFromRectangle(rectangle *shape.Rectangle) shape.IShape { + return rectangle // неявное приведение + // return shape.IShape(rectangle) // явное приведение +} + +func main() { + rectangle := shape.NewRectangle(10, 6, shape.Point{X: 6, Y: -8}, "Gold") + + ishape := shape.IShape(rectangle) // приведение Rectangle к интерфейсу + // приведение интерфейса IShape к интерфейсу IShapeArea + iShapeArea := shape.IShapeArea(ishape) + fmt.Printf("IShapeArea: %+v\n", iShapeArea.GetArea()) + + // явное обратное приведение интерфейса IShapePerimeter к интерфейсу IShape невозможно + // ishape = shape.IShape(iShapePerimeter) //error: + // cannot convert iShapePerimeter (variable of type shape.IShapePerimeter) to shape.IShape + // (shape.IShapePerimeter does not implement shape.IShape (missing method GetArea)) + + // правильное приведение интерфейса IShapeArea к интерфейсу IShape + ishape = iShapeArea.(*shape.Rectangle) + // аналогично + // newIshape := shape.IShape(iShapeArea.(*shape.Rectangle)) + fmt.Printf("IShape center: %+v\n", ishape.GetCenter()) + + // правильное приведение интерфейса IShapeArea к структуре Rectangle + rectangle = iShapeArea.(*shape.Rectangle) + fmt.Printf("%s: %+v\n", rectangle.GetName(), *rectangle) +} + +// func main() { +// rectangle1 := shape.NewRectangle(10, 6, shape.Point{X: 6, Y: -8}, "Gold") +// triangle1 := shape.NewTriangle(6, 10, 8, shape.Point{X: -85, Y: 15}, "Green") +// rectangle2 := shape.NewRectangle(3, 5, shape.Point{X: 46, Y: -48}, "Yellow") +// triangle2 := shape.NewTriangle(4, 8, 6, shape.Point{X: 61, Y: 98}, "Orange") + +// // объявляем и инициализируем срез интерфейсного типа +// ishapeSlice := []shape.IShape{ +// rectangle1, +// triangle1, +// triangle2, +// rectangle2, +// } + +// for _, it := range ishapeSlice { +// fmt.Printf("Shape center coordinate: %+v\n", it.GetCenter()) +// newCenter := shape.Point{ +// X: it.GetCenter().X + 33, +// Y: it.GetCenter().Y - 20, +// } +// it.MoveCenter(newCenter) +// fmt.Printf("Shape new center coordinate: %+v\n", it.GetCenter()) +// fmt.Println() +// } +// } + +// func main() { +// rectangle := shape.NewRectangle(10, 6, shape.Point{X: 6, Y: -8}, "Gold") +// triangle := shape.NewTriangle(6, 10, 8, shape.Point{X: -85, Y: 15}, "Green") +// printShapeName(rectangle) // неявное приведение +// //printShapeName(shape.IShapeName(rectangle)) // явное приведение +// printShapeName(triangle) +// ishape := getIShapeFromRectangle(rectangle) +// fmt.Printf("Shape center: %v\n", ishape.GetCenter()) +// fmt.Printf("Shape perimeter: %v\n", ishape.GetPerimeter()) +// } + +// func main() { +// rectangle := shape.NewRectangle(10, 6, shape.Point{X: 6, Y: -8}, "Gold") +// triangle := shape.NewTriangle(6, 10, 8, shape.Point{X: -85, Y: 15}, "Green") +// iShapeName := shape.IShapeName(triangle) // приведение Triangle к интерфейсу +// fmt.Printf("IShapeName: %v\n", iShapeName.GetName()) +// iShapeName = shape.IShapeName(rectangle) // приведение Rectangle к интерфейсу +// fmt.Printf("IShapeName: %v\n", iShapeName.GetName()) +// } diff --git a/part_5/5.7/golang/factory/shape/ishape.go b/part_5/5.7/golang/factory/shape/ishape.go new file mode 100644 index 0000000..b198f49 --- /dev/null +++ b/part_5/5.7/golang/factory/shape/ishape.go @@ -0,0 +1,20 @@ +package shape + +type IShape interface { + GetArea() float64 + GetPerimeter() uint + MoveCenter(point Point) + GetCenter() Point +} + +type IShapeArea interface { + GetArea() float64 +} + +type IShapePerimeter interface { + GetPerimeter() uint +} + +type IShapeName interface { + GetName() string +} diff --git a/part_5/5.7/golang/factory/shape/rectangle.go b/part_5/5.7/golang/factory/shape/rectangle.go new file mode 100644 index 0000000..54a960d --- /dev/null +++ b/part_5/5.7/golang/factory/shape/rectangle.go @@ -0,0 +1,47 @@ +package shape + +type Rectangle struct { + shape // композиция + width uint + length uint +} + +func (r *Rectangle) GetWidth() uint { + return r.width +} + +func (r *Rectangle) GetLength() uint { + return r.length +} + +func (r *Rectangle) SetWidth(width uint) { + r.width = width +} + +func (r *Rectangle) SetLength(length uint) { + r.length = length +} + +func (r *Rectangle) GetPerimeter() uint { + return (r.length + r.width) * 2 +} + +func (r *Rectangle) GetArea() float64 { + return float64(r.length * r.width) +} + +func (r *Rectangle) GetName() string { + return "Super-puper " + r.shape.GetName() +} + +func NewRectangle(width, length uint, center Point, color string) *Rectangle { + return &Rectangle{ + shape: shape{ + name: "Rectangle", + color: color, + center: center, + }, + width: width, + length: length, + } +} diff --git a/part_5/5.7/golang/factory/shape/shape.go b/part_5/5.7/golang/factory/shape/shape.go new file mode 100644 index 0000000..abf361b --- /dev/null +++ b/part_5/5.7/golang/factory/shape/shape.go @@ -0,0 +1,32 @@ +package shape + +type Point struct { + X int + Y int +} + +type shape struct { + name string + center Point + color string +} + +func (s *shape) SetColor(color string) { + s.color = color +} + +func (s *shape) GetColor() string { + return s.color +} + +func (s *shape) GetName() string { + return s.name +} + +func (s *shape) MoveCenter(point Point) { + s.center = point +} + +func (s *shape) GetCenter() Point { + return s.center +} diff --git a/part_5/5.7/golang/factory/shape/triangle.go b/part_5/5.7/golang/factory/shape/triangle.go new file mode 100644 index 0000000..fdf1a8a --- /dev/null +++ b/part_5/5.7/golang/factory/shape/triangle.go @@ -0,0 +1,64 @@ +package shape + +import "math" + +type Triangle struct { + shape + abLength uint + acLength uint + bcLength uint +} + +func (t *Triangle) GetABLength() uint { + return t.abLength +} + +func (t *Triangle) GetACLength() uint { + return t.acLength +} + +func (t *Triangle) GetBCLength() uint { + return t.bcLength +} + +func (t *Triangle) SetABLength(ab uint) { + t.abLength = ab +} + +func (t *Triangle) SetACLength(ac uint) { + t.abLength = ac +} + +func (t *Triangle) SetBCLength(bc uint) { + t.abLength = bc +} + +func (t *Triangle) GetPerimeter() uint { + return t.abLength + t.acLength + t.bcLength +} + +func (t *Triangle) GetArea() float64 { + // расчет площади треугольника + // высота рассчитывается по формуле разностороннего треугольника + // через длины всех сторон + p := float64(t.GetPerimeter() / 2) // полупериметр + numerator := p * (p - float64(t.abLength)) * + (p - float64(t.acLength)) * + (p - float64(t.acLength)) + numerator = 2 * math.Sqrt(numerator) + height := numerator / 2 + return float64(t.acLength) / 2 * height +} + +func NewTriangle(ab, ac, bc uint, center Point, color string) *Triangle { + return &Triangle{ + shape: shape{ + name: "Triangle", + color: color, + center: center, + }, + abLength: ab, + bcLength: bc, + acLength: ac, + } +} diff --git a/part_5/5.8/golang/car_factory/go.mod b/part_5/5.8/golang/car_factory/go.mod new file mode 100644 index 0000000..aad1e88 --- /dev/null +++ b/part_5/5.8/golang/car_factory/go.mod @@ -0,0 +1,3 @@ +module golang/car_factory + +go 1.24 diff --git a/part_5/5.8/golang/car_factory/main.go b/part_5/5.8/golang/car_factory/main.go new file mode 100644 index 0000000..46461b4 --- /dev/null +++ b/part_5/5.8/golang/car_factory/main.go @@ -0,0 +1,35 @@ +package main + +import ( + "fmt" + "golang/car_factory/vehicle" + "golang/car_factory/vehicle/motor" +) + +func printCarInfo(car *vehicle.Car) { + fmt.Printf("----------- %v -----------\n", car.GetBrand()) + fmt.Printf("Car: %+v\n", car) + fmt.Printf("motor: %+v\n", car.GetMotorData()) + fmt.Println() +} + +func main() { + car := vehicle.NewDefaultCar() + printCarInfo(car) + car.StartMove() + car.StartMotor() + car.StartMove() + car.StoptMotor() + fmt.Println("Is car move? ", car.IsMove()) + + // меняем двигатель + newMotor := motor.NewHyundaiMotor("1.8") + car.ChangeMotor(newMotor) + + printCarInfo(car) + printCarInfo(car) + car.StartMove() + car.StartMotor() + car.StartMove() + fmt.Println("Is car move? ", car.IsMove()) +} diff --git a/part_5/5.8/golang/car_factory/vehicle/car.go b/part_5/5.8/golang/car_factory/vehicle/car.go new file mode 100644 index 0000000..ed5ad4f --- /dev/null +++ b/part_5/5.8/golang/car_factory/vehicle/car.go @@ -0,0 +1,87 @@ +package vehicle + +import ( + "fmt" + "golang/car_factory/vehicle/motor" +) + +type Car struct { + motor motor.IMotor + isLeftHandDrive bool + brand string + isMove bool +} + +func (c *Car) GetBrand() string { + return c.brand +} + +func (c *Car) ChangeMotor(motor motor.IMotor) { + fmt.Println() + fmt.Println("-------- Change Motor --------") + fmt.Printf("Old motor: %+v\n", c.motor) + c.motor = motor + fmt.Printf("New motor: %+v\n", c.motor) + fmt.Println() +} + +func (c *Car) IsLeftHandDrive() bool { + return c.isLeftHandDrive +} + +func (c *Car) StartMotor() { + c.motor.RunMotor() +} + +func (c *Car) StoptMotor() { + c.motor.StopMotor() + c.isMove = false +} + +func (c *Car) StartMove() { + if c.motor.IsRun() { + c.isMove = true + fmt.Printf("Сar '%v' started moving\n", c.brand) + } else { + fmt.Printf("Сar '%v' can't start moving\n", c.brand) + } +} + +func (c *Car) StopMove() { + if c.isMove { + c.isMove = false + fmt.Printf("Сar '%v' stopped \n", c.brand) + } else { + fmt.Println("To stop first start moving") + } +} + +func (c *Car) GetMotorData() string { + return fmt.Sprintf("%+v", c.motor) +} + +func (c *Car) GetMotorPower() string { + return c.motor.GetPower() +} + +func (c *Car) IsMove() bool { + return c.isMove +} + +func NewCar(brand string, motor motor.IMotor, isLeftHandDrive bool) *Car { + return &Car{ + motor: motor, + brand: brand, + isLeftHandDrive: isLeftHandDrive, + isMove: false, + } +} + +func NewDefaultCar() *Car { + return &Car{ + motor: motor.NewAutoVazMotor("1.6"), + brand: "Lada", + isLeftHandDrive: false, + isMove: false, + } +} diff --git a/part_5/5.8/golang/car_factory/vehicle/motor/avtovaz_motor.go b/part_5/5.8/golang/car_factory/vehicle/motor/avtovaz_motor.go new file mode 100644 index 0000000..014ec4c --- /dev/null +++ b/part_5/5.8/golang/car_factory/vehicle/motor/avtovaz_motor.go @@ -0,0 +1,23 @@ +package motor + +type AvtoVazMotor struct { + Motor +} + +func NewAutoVazMotor(power string) *AvtoVazMotor { + motor := &AvtoVazMotor{ + Motor: Motor{ + manufacturer: autoVAZ, + isRun: false, + }, + } + switch power { + case "1.6": + motor.amountСylinders = 4 + motor.power = power + default: + motor.amountСylinders = 4 + motor.power = defaultPower + } + return motor +} diff --git a/part_5/5.8/golang/car_factory/vehicle/motor/hyundai_motor.go b/part_5/5.8/golang/car_factory/vehicle/motor/hyundai_motor.go new file mode 100644 index 0000000..a98918d --- /dev/null +++ b/part_5/5.8/golang/car_factory/vehicle/motor/hyundai_motor.go @@ -0,0 +1,40 @@ +package motor + +type HyundaiMotor struct { + Motor + turboMod bool +} + +func (m *HyundaiMotor) IsTurboModOn() bool { + return m.turboMod +} + +func (m *HyundaiMotor) TurboModOn() { + m.turboMod = true +} + +func (m *HyundaiMotor) TurboModoff() { + m.turboMod = false +} + +func NewHyundaiMotor(power string) *HyundaiMotor { + motor := &HyundaiMotor{ + Motor: Motor{ + manufacturer: hyundai, + isRun: false, + }, + turboMod: false, + } + switch power { + case "1.8": + motor.amountСylinders = 6 + motor.power = power + case "1.6": + motor.amountСylinders = 4 + motor.power = power + default: + motor.amountСylinders = 4 + motor.power = defaultPower + } + return motor +} diff --git a/part_5/5.8/golang/car_factory/vehicle/motor/imotor.go b/part_5/5.8/golang/car_factory/vehicle/motor/imotor.go new file mode 100644 index 0000000..79c42c2 --- /dev/null +++ b/part_5/5.8/golang/car_factory/vehicle/motor/imotor.go @@ -0,0 +1,10 @@ +package motor + +type IMotor interface { + GetPower() string + RunMotor() + StopMotor() + IsRun() bool + AmountСylinders() uint8 + GetManufacturerName() string +} diff --git a/part_5/5.8/golang/car_factory/vehicle/motor/motor.go b/part_5/5.8/golang/car_factory/vehicle/motor/motor.go new file mode 100644 index 0000000..64d0e26 --- /dev/null +++ b/part_5/5.8/golang/car_factory/vehicle/motor/motor.go @@ -0,0 +1,40 @@ +package motor + +import "fmt" + +const hyundai = "Hyundai" +const autoVAZ = "Автоваз" +const defaultPower = "1.4" + +type Motor struct { + power string + amountСylinders uint8 + isRun bool + manufacturer string +} + +func (m *Motor) GetPower() string { + return m.power +} + +func (m *Motor) RunMotor() { + fmt.Println("Motor is run") + m.isRun = true +} + +func (m *Motor) StopMotor() { + fmt.Println("Motor is stop") + m.isRun = false +} + +func (m *Motor) IsRun() bool { + return m.isRun +} + +func (m *Motor) AmountСylinders() uint8 { + return m.amountСylinders +} + +func (m *Motor) GetManufacturerName() string { + return m.manufacturer +} diff --git a/part_5/5.9/1.go b/part_5/5.9/1.go new file mode 100644 index 0000000..d258ca5 --- /dev/null +++ b/part_5/5.9/1.go @@ -0,0 +1,8 @@ +package main + +import "fmt" + +func main() { + var myInterface interface{} + fmt.Printf("%v", myInterface) // +} diff --git a/part_5/5.9/2.go b/part_5/5.9/2.go new file mode 100644 index 0000000..8fd06d4 --- /dev/null +++ b/part_5/5.9/2.go @@ -0,0 +1,19 @@ +package main + +import "fmt" + +type shape struct { + name string +} + +func (s *shape) getName() string { + return s.name +} + +func main() { + var firstInterface interface{} = shape{name: "Cube"} + var secondInterface interface{} = "Oo" + + fmt.Printf("%+v\n", firstInterface) // {name:Cube} + fmt.Printf("%+v\n", secondInterface) // Oo +} diff --git a/part_5/5.9/3.go b/part_5/5.9/3.go new file mode 100644 index 0000000..13210c9 --- /dev/null +++ b/part_5/5.9/3.go @@ -0,0 +1,20 @@ +package main + +import "fmt" + +type shape struct { + name string +} + +func (s *shape) getName() string { + return s.name +} + +func main() { + var firstInterface interface{} = shape{name: "Cube"} + var secondInterface interface{} = "Oo" + + fmt.Printf("%+v\n", secondInterface.(string)) // ok + fmt.Printf("%+v\n", firstInterface.(string)) // error + +} diff --git a/part_5/5.9/4.go b/part_5/5.9/4.go new file mode 100644 index 0000000..c25e45e --- /dev/null +++ b/part_5/5.9/4.go @@ -0,0 +1,30 @@ +package main + +import "fmt" + +type shape struct { + name string +} + +func (s *shape) getName() string { + return s.name +} + +func main() { + var firstInterface interface{} = shape{name: "Cube"} + value, ok := firstInterface.(string) + + if ok { + fmt.Println(value) // работаем со значением + } else { + fmt.Println("Wrong type assertion!") + } + + newValue, newOk := firstInterface.(shape) + + if newOk { + fmt.Println(newValue.getName()) + } else { + fmt.Println("Wrong type assertion!") + } +} diff --git a/part_5/5.9/5.go b/part_5/5.9/5.go new file mode 100644 index 0000000..87e3791 --- /dev/null +++ b/part_5/5.9/5.go @@ -0,0 +1,23 @@ +package main + +import "fmt" + +type shape struct{} +type car struct{} + +func checkType(i interface{}) { + switch i.(type) { + case shape: + fmt.Println("It is shape") + case car: + fmt.Println("It is car") + default: + fmt.Println("What is this pokemon?") + } +} + +func main() { + checkType(shape{}) + checkType(car{}) + checkType(6) +} diff --git a/part_5/5.9/6.go b/part_5/5.9/6.go new file mode 100644 index 0000000..379d8e3 --- /dev/null +++ b/part_5/5.9/6.go @@ -0,0 +1,24 @@ +package main + +import "fmt" + +type shape struct{} +type car struct{} + +func isEqual(i interface{}, j interface{}) { + if i == j { // одинаковое значение и базовый тип? + fmt.Println("Equal") + } else { + fmt.Println("Inequal") + } +} + +func main() { + isEqual(shape{}, shape{}) // Equal + isEqual(shape{}, car{}) // Inequal + + var firstInterface interface{} // по умолчанию - nil + var secondInterface interface{} + + isEqual(firstInterface, secondInterface) // Equal +} diff --git a/part_6/6.1/1.go b/part_6/6.1/1.go new file mode 100644 index 0000000..1c49a7a --- /dev/null +++ b/part_6/6.1/1.go @@ -0,0 +1,11 @@ +import "fmt" + +func main() { + names := []string{ + "Alex", + "Max", + "German", + } + + fmt.Printf("My name is %v", names[3]) +} diff --git a/part_6/6.1/2.go b/part_6/6.1/2.go new file mode 100644 index 0000000..71a6ee2 --- /dev/null +++ b/part_6/6.1/2.go @@ -0,0 +1,32 @@ +package main + +import "fmt" + +type Person struct { + name string + age uint8 +} + +func (p *Person) getName() string { + return p.name +} + +func (p *Person) getAge() uint8 { + return p.age +} + +func (p *Person) incAge() { + p.age++ +} + +func main() { + alex := &Person{ + name: "Alex", + age: 26, + } + fmt.Printf("Person data: %+v\n", alex) + alex.incAge() + fmt.Printf("Person data: %+v\n", alex) + alex = nil + alex.incAge() +} diff --git a/part_6/6.2/1.go b/part_6/6.2/1.go new file mode 100644 index 0000000..7600bb3 --- /dev/null +++ b/part_6/6.2/1.go @@ -0,0 +1,27 @@ +package main + +import "fmt" + +type Person struct { + name string + age uint8 +} + +func (p *Person) incAge() { + p.age++ + if p.age > 30 { + panic(fmt.Sprintf("%s too old!!!", p.name)) + } +} + +func main() { + + alex := &Person{ + name: "Alex", + age: 27, + } + for i := 0; i < 6; i++ { + alex.incAge() + } + fmt.Printf("Person data: %+v\n", alex) +} diff --git a/part_6/6.3/1.go b/part_6/6.3/1.go new file mode 100644 index 0000000..a70cd11 --- /dev/null +++ b/part_6/6.3/1.go @@ -0,0 +1,33 @@ +package main + +import "fmt" + +type Person struct { + name string + age uint8 +} + +func (p *Person) incAge() { + p.age++ + if p.age > 30 { + defer func() { + fmt.Println("Calling defer function") + }() + panic(fmt.Sprintf("%s too old!!!", p.name)) + defer func() { // нет смысла в вызове отложенной функции после паники + fmt.Println("Useless function") + }() + } +} + +func main() { + + alex := &Person{ + name: "Alex", + age: 27, + } + for i := 0; i < 6; i++ { + alex.incAge() + } + fmt.Printf("Person data: %+v\n", alex) +} diff --git a/part_6/6.4/1.go b/part_6/6.4/1.go new file mode 100644 index 0000000..b6b662c --- /dev/null +++ b/part_6/6.4/1.go @@ -0,0 +1,35 @@ +package main + +import ( + "fmt" + "log" +) + +type Person struct { + name string + age uint8 +} + +func (p *Person) incAge() { + p.age++ + if p.age > 30 { + defer func() { + if err := recover(); err != nil { + log.Printf("%s has a new life, he (she) is %d years old", p.name, p.age) + } + }() + panic(fmt.Sprintf("%s too old!!!", p.name)) + } +} + +func main() { + + alex := &Person{ + name: "Alex", + age: 27, + } + for i := 0; i < 6; i++ { + alex.incAge() + } + fmt.Printf("Person data: %+v\n", alex) +} diff --git a/part_6/6.4/2.go b/part_6/6.4/2.go new file mode 100644 index 0000000..f273702 --- /dev/null +++ b/part_6/6.4/2.go @@ -0,0 +1,44 @@ +package main + +import ( + "fmt" + "log" +) + +type Person struct { + name string + age uint8 +} + +func (p *Person) incAge() { + p.age++ + if p.age > 30 { + defer func() { + if err := recover(); err != nil { + log.Printf("%s has a new life, he (she) is %d years old", p.name, p.age) + if p.age > 35 { + panic(fmt.Sprintf("%s super old!!!", p.name)) + } + } + }() + panic(fmt.Sprintf("%s too old!!!", p.name)) + } +} + +func main() { + + alex := &Person{ + name: "Alex", + age: 27, + } + + defer func() { + if err := recover(); err != nil { + log.Printf("%s, welcome to club: 'А вот в наши времена'", alex.name) + } + }() + for i := 0; i < 20; i++ { + alex.incAge() + } + fmt.Printf("Person data: %+v\n", alex) +} diff --git a/part_6/6.5/1.go b/part_6/6.5/1.go new file mode 100644 index 0000000..f8ba208 --- /dev/null +++ b/part_6/6.5/1.go @@ -0,0 +1,22 @@ +package main + +import ( + "fmt" + "strconv" +) + +func main() { + var str string = "10" + value, err := strconv.Atoi(str) // преобразование строки в целочисленное значение + if err != nil { // если err != nil, то обрабатываем ошибку + value = 22 + } + fmt.Println(value) // 10 + + str = "2we" + value, err = strconv.Atoi(str) + if err != nil { // если err != nil, то обрабатываем ошибку + value = 22 + } + fmt.Println(value) // 22 +} diff --git a/part_6/6.5/2.go b/part_6/6.5/2.go new file mode 100644 index 0000000..734ba53 --- /dev/null +++ b/part_6/6.5/2.go @@ -0,0 +1,12 @@ +package main + +import ( + "errors" + "fmt" +) + +func main() { + myError1 := errors.New("first error") + myError2 := fmt.Errorf("second error") + fmt.Println(myError1, myError2) // first error second error +} diff --git a/part_6/6.5/3.go b/part_6/6.5/3.go new file mode 100644 index 0000000..62eda47 --- /dev/null +++ b/part_6/6.5/3.go @@ -0,0 +1,25 @@ +package main + +import "fmt" + +func div(a, b int) (int, error) { + if b == 0 { + return 0, fmt.Errorf("Сan't divide '%v' by zero", a) + } + return a / b, nil +} + +func printResult(result int, err error) { + if err != nil { + fmt.Println(err) + } else { + fmt.Println(result) + } +} + +func main() { + a, b := 10, 2 + printResult(div(a, b)) // 5 + a, b = 4, 0 + printResult(div(a, b)) // Сan't divide '4' by zero +} diff --git a/part_6/6.6/1.go b/part_6/6.6/1.go new file mode 100644 index 0000000..90c8f91 --- /dev/null +++ b/part_6/6.6/1.go @@ -0,0 +1,31 @@ +package main + +import ( + "errors" + "fmt" +) + +// Объявление пользовательского варианта ошибки деления на ноль +var ErrDivByZero = errors.New("divide by zero") + +func div(a, b int) (int, error) { + if b == 0 { + return 0, ErrDivByZero + } + return a / b, nil +} + +func printResult(result int, err error) { + if err != nil { + fmt.Println(err) + } else { + fmt.Println(result) + } +} + +func main() { + a, b := 10, 2 + printResult(div(a, b)) // 5 + a, b = 4, 0 + printResult(div(a, b)) // divide by zero +} diff --git a/part_6/6.7/1.go b/part_6/6.7/1.go new file mode 100644 index 0000000..95e616c --- /dev/null +++ b/part_6/6.7/1.go @@ -0,0 +1,41 @@ +package main + +import ( + "errors" + "fmt" +) + +var ErrDivByZero = errors.New("divide by zero") +var ErrDivByOne = errors.New("divide by one") + +func div(a, b int) (int, error) { + if b == 0 { + return 0, ErrDivByZero + } + if b == 1 { + return a, ErrDivByOne + } + return a / b, nil +} + +func printResult(result int, err error) { + if err != nil { + switch { + case errors.Is(err, ErrDivByZero): + fmt.Println(err) + case errors.Is(err, ErrDivByOne): + fmt.Printf("result = %d, but was %v\n", result, err) + default: + fmt.Printf("unexpected error: %v\n", err) + } + + } else { + fmt.Println(result) + } +} + +func main() { + printResult(div(10, 2)) // 5 + printResult(div(4, 0)) // divide by zero + printResult(div(12, 1)) // result = 12, but was divide by one +} diff --git a/part_6/6.8/1.go b/part_6/6.8/1.go new file mode 100644 index 0000000..0c231e8 --- /dev/null +++ b/part_6/6.8/1.go @@ -0,0 +1,62 @@ +package main + +import ( + "errors" + "fmt" +) + +type DivError struct { + Numerator int + Denominator int + Msg string +} + +func (d *DivError) Error() string { + return d.Msg +} + +func div(a, b int) (int, error) { + if b == 0 { + return 0, &DivError{ + Numerator: a, + Denominator: b, + Msg: fmt.Sprintf("Сan't divide '%v' by zero", a), + } + } + if b == 1 { + return a, &DivError{ + Numerator: a, + Denominator: b, + Msg: "Divide by one", + } + } + return a / b, nil +} + +func printResult(result int, err error) { + if err != nil { + var myDivError *DivError + switch { + case errors.As(err, &myDivError): + fmt.Printf("Numerator: %d, Denominator: %d, Error: %s\n", + myDivError.Numerator, myDivError.Denominator, myDivError.Msg) + if myDivError.Denominator == 1 { + fmt.Printf("result = %d, but was %v\n", + myDivError.Numerator, myDivError.Msg) + } + default: + fmt.Printf("unexpected error: %v\n", err) + } + + } else { + fmt.Println(result) + } +} + +func main() { + printResult(div(10, 2)) // 5 + printResult(div(4, 0)) // Numerator: 4, Denominator: 0, Error: Сan't divide '4' by zero + printResult(div(12, 1)) + // Numerator: 12, Denominator: 1, Error: Divide by one + // result = 12, but was divide by one +} diff --git a/part_6/6.9/1.go b/part_6/6.9/1.go new file mode 100644 index 0000000..dd77ecf --- /dev/null +++ b/part_6/6.9/1.go @@ -0,0 +1,122 @@ +package main + +import ( + "errors" + "fmt" +) + +type User struct { + ID uint + Name string + Age uint8 +} + +type UserDB struct { + users []User +} + +func (db *UserDB) FindUserWithID(id uint) (*User, error) { + for _, it := range db.users { + if it.ID == id { + return &it, nil + } + } + return nil, fmt.Errorf("User with id=%v not found", id) +} + +func (db *UserDB) SetUserAge(id uint, age uint8) error { + for _, it := range db.users { + if it.ID == id { + it.Age = age + return nil + } + } + return fmt.Errorf("User with id=%v not found", id) +} + +func (db *UserDB) AddUser(user User) error { + for _, it := range db.users { + if it.ID == user.ID { + return fmt.Errorf("User with id=%v already exist", user.ID) + } + } + db.users = append(db.users, user) + return nil +} + +func (db *UserDB) DeleteUserWithName(name string) error { + index := -1 + for idx, it := range db.users { + if it.Name == name { + index = idx + break + } + } + if index < 0 { + return fmt.Errorf("User %s not found", name) + } + db.users = append(db.users[:index], db.users[index+1:]...) + return nil +} + +// функции для работы с БД и организации цепочек ошибок +func findUserWithID(db *UserDB, id uint) (*User, error) { + user, err := db.FindUserWithID(id) + if err != nil { + // вернется ошибка из 2-х вложений + return nil, fmt.Errorf("DataBase error: %w", err) + } + return user, nil +} + +func setUserAge(db *UserDB, id uint, age uint8) error { + err := db.SetUserAge(id, age) + if err != nil { + // вернется ошибка из 2-х вложений + return fmt.Errorf("DataBase user data error: %w", err) + } + return nil +} + +func addUser(db *UserDB, user User) error { + err := db.AddUser(user) + if err != nil { + // вернется ошибка из 2-х вложений + return fmt.Errorf("Add user error: %w", err) + } + return nil +} + +func main() { + dbUsers := UserDB{ + []User{ + {2, "Alex", 28}, + {1, "Max", 23}, + {10, "German", 35}, + {6, "Oleg", 19}, + }, + } + + user, err := findUserWithID(&dbUsers, 2) + if err != nil { + fmt.Println(err) + // распаковка трассировки ошибок + fmt.Println(errors.Unwrap(err)) + } + fmt.Printf("%+v\n", user) // &{ID:2 Name:Alex Age:28} + + user, err = findUserWithID(&dbUsers, 12) + if err != nil { + fmt.Println(err) // DataBase error: User with id=12 not found + // распаковка трассировки ошибок + fmt.Println(errors.Unwrap(err)) // User with id=12 not found + } + fmt.Printf("%+v\n", user) // + + newErr := addUser(&dbUsers, User{6, "Li", 45}) + if newErr != nil { + fmt.Println(newErr) // Add user error: User with id=6 already exist + // распаковка трассировки ошибок + fmt.Println(errors.Unwrap(newErr)) // User with id=6 already exist + } +} diff --git a/part_7/7.1 file/1.go b/part_7/7.1 file/1.go new file mode 100644 index 0000000..76c4e2a --- /dev/null +++ b/part_7/7.1 file/1.go @@ -0,0 +1,16 @@ +package main + +import ( + "fmt" + "log" + "os" +) + +func main() { + file, err := os.Create("test.txt") + if err != nil { + log.Fatal(err) + } + fmt.Println(file) + file.Close() // закрытие файла +} diff --git a/part_7/7.1 file/10.go b/part_7/7.1 file/10.go new file mode 100644 index 0000000..530d620 --- /dev/null +++ b/part_7/7.1 file/10.go @@ -0,0 +1,15 @@ +package main + +import ( + "fmt" + "log" + "os" +) + +func main() { + data, err := os.ReadFile("pirates.txt") + if err != nil { + log.Fatal(err) + } + fmt.Println(string(data)) +} diff --git a/part_7/7.1 file/11.go b/part_7/7.1 file/11.go new file mode 100644 index 0000000..df6854d --- /dev/null +++ b/part_7/7.1 file/11.go @@ -0,0 +1,25 @@ +package main + +import ( + "bufio" + "fmt" + "log" + "os" +) + +func main() { + file, err := os.Open("pirates.txt") + if err != nil { + log.Fatal(err) + } + defer file.Close() + + scanner := bufio.NewScanner(file) + for scanner.Scan() { + fmt.Println(scanner.Text()) + } + + if err := scanner.Err(); err != nil { + log.Fatal(err) + } +} diff --git a/part_7/7.1 file/12.go b/part_7/7.1 file/12.go new file mode 100644 index 0000000..29f11b4 --- /dev/null +++ b/part_7/7.1 file/12.go @@ -0,0 +1,26 @@ +package main + +import ( + "bufio" + "fmt" + "log" + "os" +) + +func main() { + file, err := os.Open("pirates.txt") + if err != nil { + log.Fatal(err) + } + defer file.Close() + + scanner := bufio.NewScanner(file) + scanner.Split(bufio.ScanWords) + for scanner.Scan() { + fmt.Println(scanner.Text()) + } + + if err := scanner.Err(); err != nil { + log.Fatal(err) + } +} diff --git a/part_7/7.1 file/13.go b/part_7/7.1 file/13.go new file mode 100644 index 0000000..4a8861d --- /dev/null +++ b/part_7/7.1 file/13.go @@ -0,0 +1,19 @@ +package main + +import ( + "log" + "os" +) + +func main() { + firstText := "Пятнадцать человек на сундук мертвеца,\n" + secondText := "Йо-хо-хо, и бутылка рома,\n" + file, err := os.OpenFile("pirates2.txt", os.O_WRONLY|os.O_CREATE, 0666) + if err != nil { + log.Fatal(err) + } + defer file.Close() + + file.WriteString(firstText) + file.WriteString(secondText) +} diff --git a/part_7/7.1 file/14.go b/part_7/7.1 file/14.go new file mode 100644 index 0000000..014b2ed --- /dev/null +++ b/part_7/7.1 file/14.go @@ -0,0 +1,19 @@ +package main + +import ( + "log" + "os" +) + +func main() { + firstText := "Пей, и дьявол тебя доведет до конца,\n" + secondText := "Йо-хо-хо, и бутылка рома!" + file, err := os.OpenFile("pirates2.txt", os.O_WRONLY, 0666) + if err != nil { + log.Fatal(err) + } + defer file.Close() + + file.WriteString(firstText) + file.WriteString(secondText) +} diff --git a/part_7/7.1 file/15.go b/part_7/7.1 file/15.go new file mode 100644 index 0000000..6a2f848 --- /dev/null +++ b/part_7/7.1 file/15.go @@ -0,0 +1,22 @@ +package main + +import ( + "fmt" + "io" + "log" + "os" +) + +func main() { + file, err := os.OpenFile("pirates2.txt", os.O_RDONLY, 0666) + if err != nil { + log.Fatal(err) + } + defer file.Close() + + data, err := io.ReadAll(file) + if err != nil { + log.Fatal(err) + } + fmt.Println(string(data)) +} diff --git a/part_7/7.1 file/16.go b/part_7/7.1 file/16.go new file mode 100644 index 0000000..ff1390c --- /dev/null +++ b/part_7/7.1 file/16.go @@ -0,0 +1,34 @@ +package main + +import ( + "fmt" + "io" + "log" + "os" +) + +func main() { + originalFile, err := os.Open("pirates2.txt") + if err != nil { + log.Fatal(err) + } + defer originalFile.Close() + + newFile, err := os.Create("pirates2_copy.txt") + if err != nil { + log.Fatal(err) + } + defer newFile.Close() + + bytesWritten, err := io.Copy(newFile, originalFile) + if err != nil { + log.Fatal(err) + } + fmt.Printf("Copied %d bytes", bytesWritten) // Copied 224 bytes + + // Фиксируем содержимое файла и осуществляем освобождение буфера + err = newFile.Sync() + if err != nil { + log.Fatal(err) + } +} diff --git a/part_7/7.1 file/17.go b/part_7/7.1 file/17.go new file mode 100644 index 0000000..5c76c24 --- /dev/null +++ b/part_7/7.1 file/17.go @@ -0,0 +1,45 @@ +package main + +import ( + "fmt" + "log" + "os" +) + +type Car struct { + model string + age uint8 + weight float64 + number string +} + +func createCars() []Car { + return []Car{ + { + model: "Oka", + weight: 13.22, + number: "ak1245j76", + age: 13, + }, + { + model: "Lada7", + weight: 23.14, + number: "ak2147j175", + age: 1, + }, + } +} + +func main() { + myFile, err := os.Create("car_fprintln.txt") + if err != nil { + log.Fatal(err) + } + defer myFile.Close() + + myCar := createCars() + for _, it := range myCar { + n, _ := fmt.Fprintln(myFile, it.model, it.number, it.age, it.weight) + fmt.Println("Записано: ", n, "байт") + } +} diff --git a/part_7/7.1 file/18.go b/part_7/7.1 file/18.go new file mode 100644 index 0000000..a9c8bba --- /dev/null +++ b/part_7/7.1 file/18.go @@ -0,0 +1,46 @@ +package main + +import ( + "fmt" + "log" + "os" +) + +type Car struct { + model string + age uint8 + weight float64 + number string +} + +func createCars() []Car { + return []Car{ + { + model: "Oka", + weight: 13.22, + number: "ak1245j76", + age: 13, + }, + { + model: "Lada7", + weight: 23.14, + number: "ak2147j175", + age: 1, + }, + } +} + +func main() { + myFile, err := os.Create("car_fprintf.txt") + if err != nil { + log.Fatal(err) + } + defer myFile.Close() + + myCar := createCars() + for _, it := range myCar { + n, _ := fmt.Fprintf(myFile, "Model: %s ||Number: %s ||Age: %d ||Weight: %f\n", + it.model, it.number, it.age, it.weight) + fmt.Println("Записано: ", n, "байт") + } +} diff --git a/part_7/7.1 file/19.go b/part_7/7.1 file/19.go new file mode 100644 index 0000000..b8bb343 --- /dev/null +++ b/part_7/7.1 file/19.go @@ -0,0 +1,39 @@ +package main + +import ( + "fmt" + "io" + "log" + "os" +) + +type Car struct { + model string + age uint8 + weight float64 + number string +} + +func main() { + myFile, err := os.Open("car_fprintln.txt") + if err != nil { + log.Fatal(err) + } + defer myFile.Close() + + myCars := []Car{} + + for { + var car Car + n, err := fmt.Fscanln(myFile, &car.model, &car.number, &car.age, &car.weight) + if err != nil { + if err == io.EOF { // Читаем до конца файла + break + } + log.Fatal(err) + } + fmt.Println("Прочитано: ", n, "элемента(-ов)") + myCars = append(myCars, car) + } + fmt.Println(myCars) +} diff --git a/part_7/7.1 file/2.go b/part_7/7.1 file/2.go new file mode 100644 index 0000000..5f817ad --- /dev/null +++ b/part_7/7.1 file/2.go @@ -0,0 +1,19 @@ +package main + +import ( + "fmt" + "log" + "os" +) + +func main() { + fileInfo, err := os.Stat("test.txt") + if err != nil { + log.Fatal(err) + } + fmt.Println("File name:", fileInfo.Name()) + fmt.Println("Size in bytes:", fileInfo.Size()) + fmt.Println("Permissions:", fileInfo.Mode()) + fmt.Println("Last modified:", fileInfo.ModTime()) + fmt.Println("Is Directory: ", fileInfo.IsDir()) +} diff --git a/part_7/7.1 file/20.go b/part_7/7.1 file/20.go new file mode 100644 index 0000000..01a34a7 --- /dev/null +++ b/part_7/7.1 file/20.go @@ -0,0 +1,40 @@ +package main + +import ( + "fmt" + "io" + "log" + "os" +) + +type Car struct { + model string + age uint8 + weight float64 + number string +} + +func main() { + myFile, err := os.Open("car_fprintf.txt") + if err != nil { + log.Fatal(err) + } + defer myFile.Close() + + myCars := []Car{} + + for { + var car Car + n, err := fmt.Fscanf(myFile, "Model: %s ||Number: %s ||Age: %d ||Weight: %f\n", + &car.model, &car.number, &car.age, &car.weight) + if err != nil { + if err == io.EOF || err.Error() == "unexpected EOF" { + break + } + log.Fatal(err) + } + fmt.Println("Прочитано: ", n, "элемента(-ов)") + myCars = append(myCars, car) + } + fmt.Println(myCars) +} diff --git a/part_7/7.1 file/3.go b/part_7/7.1 file/3.go new file mode 100644 index 0000000..0979981 --- /dev/null +++ b/part_7/7.1 file/3.go @@ -0,0 +1,17 @@ +package main + +import ( + "log" + "os" +) + +func main() { + originalPath := "test.txt" + newPath := "../test2.txt" // переместит файл на уровень выше с именем test2.txt + // можно также оставить старое имя у перемещаемого файла - test.txt + // newPath := "test2.txt" // переименование файла в текущей директории + err := os.Rename(originalPath, newPath) + if err != nil { + log.Fatal(err) + } +} diff --git a/part_7/7.1 file/4.go b/part_7/7.1 file/4.go new file mode 100644 index 0000000..d0bed69 --- /dev/null +++ b/part_7/7.1 file/4.go @@ -0,0 +1,14 @@ +package main + +import ( + "log" + "os" +) + +func main() { + pathToFile := "test.txt" + err := os.Remove(pathToFile) + if err != nil { + log.Fatal(err) + } +} diff --git a/part_7/7.1 file/5.go b/part_7/7.1 file/5.go new file mode 100644 index 0000000..b099084 --- /dev/null +++ b/part_7/7.1 file/5.go @@ -0,0 +1,20 @@ +package main + +import ( + "fmt" + "log" + "os" +) + +func main() { + pathToFile := "pirates.txt" + fileInfo, err := os.Stat(pathToFile) + if err != nil { + if os.IsNotExist(err) { + log.Fatal("File does not exist.") + os.Exit(1) // выход из приложения со статусом 1 + } + } + fmt.Println("File does exist!") + fmt.Println("File information:", fileInfo) +} diff --git a/part_7/7.1 file/6.go b/part_7/7.1 file/6.go new file mode 100644 index 0000000..f2006bb --- /dev/null +++ b/part_7/7.1 file/6.go @@ -0,0 +1,23 @@ +package main + +import ( + "fmt" + "log" + "os" +) + +func main() { + firstText := "Пятнадцать человек на сундук мертвеца,\n" + secondText := "Йо-хо-хо, и бутылка рома," + file, err := os.Create("pirates.txt") + if err != nil { + log.Fatal(err) + } + defer file.Close() + + // функция WriteString преобразует string в []byte, после чего записывает в файл + file.WriteString(firstText) + // ручное приведение типа string в []byte и запись данных в файл + file.Write([]byte(secondText)) + fmt.Println("Text was wrote to file") +} diff --git a/part_7/7.1 file/7.go b/part_7/7.1 file/7.go new file mode 100644 index 0000000..5b7f4ba --- /dev/null +++ b/part_7/7.1 file/7.go @@ -0,0 +1,29 @@ +package main + +import ( + "fmt" + "io" + "log" + "os" +) + +func main() { + file, err := os.Open("pirates.txt") + if err != nil { + log.Fatal(err) + } + defer file.Close() + + file.WriteString("jgjgjg") // ничего в файл не добавится!!! + data := make([]byte, 128) + for { + length, err := file.Read(data) + fmt.Printf("Reading %d byte\n", length) + if err == io.EOF { // достигли конца файла? + break + } + } + fmt.Println(string(data)) + + fmt.Println("Text was read from file") +} diff --git a/part_7/7.1 file/8.go b/part_7/7.1 file/8.go new file mode 100644 index 0000000..d8e425a --- /dev/null +++ b/part_7/7.1 file/8.go @@ -0,0 +1,28 @@ +package main + +import ( + "fmt" + "io" + "log" + "os" +) + +func main() { + file, err := os.Open("pirates.txt") + if err != nil { + log.Fatal(err) + } + defer file.Close() + + tempData := make([]byte, 32) + data := []byte{} + for { + length, err := file.Read(tempData) + fmt.Printf("Reading %d byte\n", length) + if err == io.EOF { // достигли конца файла? + break + } + data = append(data, tempData...) + } + fmt.Println(string(data)) +} diff --git a/part_7/7.1 file/9.go b/part_7/7.1 file/9.go new file mode 100644 index 0000000..e5b6201 --- /dev/null +++ b/part_7/7.1 file/9.go @@ -0,0 +1,22 @@ +package main + +import ( + "fmt" + "io/ioutil" + "log" + "os" +) + +func main() { + file, err := os.Open("pirates.txt") + if err != nil { + log.Fatal(err) + } + defer file.Close() + + data, err := ioutil.ReadAll(file) + if err != nil { + log.Fatal(err) + } + fmt.Println(string(data)) +} diff --git a/part_7/7.2 dir/1.go b/part_7/7.2 dir/1.go new file mode 100644 index 0000000..111f707 --- /dev/null +++ b/part_7/7.2 dir/1.go @@ -0,0 +1,15 @@ +package main + +import ( + "fmt" + "log" + "os" +) + +func main() { + err := os.Mkdir("myDir", 0777) + if err != nil { + log.Fatal(err) + } + fmt.Println("Directory created") +} diff --git a/part_7/7.2 dir/10.go b/part_7/7.2 dir/10.go new file mode 100644 index 0000000..5c269f5 --- /dev/null +++ b/part_7/7.2 dir/10.go @@ -0,0 +1,26 @@ +package main + +import ( + "fmt" + "io/fs" + "path/filepath" +) + +func main() { + countDirs := 0 + countFiles := 0 + filepath.WalkDir("C:\\Go", func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if !d.IsDir() { + countFiles++ + } else { + countDirs++ + } + return nil + }) + + fmt.Printf("Amount of files: %d\n", countFiles) + fmt.Printf("Amount of directories: %d\n", countDirs) +} diff --git a/part_7/7.2 dir/11.go b/part_7/7.2 dir/11.go new file mode 100644 index 0000000..ee040f8 --- /dev/null +++ b/part_7/7.2 dir/11.go @@ -0,0 +1,22 @@ +package main + +import ( + "log" + "os" +) + +func createDirWithFile() { + os.Mkdir("myDir", 0777) + myFile, err := os.Create("myDir\\test.dat") + if err != nil { + log.Fatal(err) + } + defer myFile.Close() +} + +func main() { + createDirWithFile() + os.Rename("myDir", "newDir") // переименование + createDirWithFile() + os.Rename("myDir", "newDir\\myDir") // перемещение +} diff --git a/part_7/7.2 dir/12.go b/part_7/7.2 dir/12.go new file mode 100644 index 0000000..89df9c0 --- /dev/null +++ b/part_7/7.2 dir/12.go @@ -0,0 +1,18 @@ +package main + +import ( + "fmt" + "os" +) + +func main() { + + pathToDir := "C:\\Go" + + if _, err := os.Stat(pathToDir); os.IsNotExist(err) { + // обработка ситуации, когда директории не существует + fmt.Println("Directory isn't exist") + } else { + fmt.Println("Directory already exists") + } +} diff --git a/part_7/7.2 dir/2.go b/part_7/7.2 dir/2.go new file mode 100644 index 0000000..b6b4272 --- /dev/null +++ b/part_7/7.2 dir/2.go @@ -0,0 +1,15 @@ +package main + +import ( + "fmt" + "log" + "os" +) + +func main() { + err := os.Remove("myDir") + if err != nil { + log.Fatal(err) + } + fmt.Println("Directory removed") +} diff --git a/part_7/7.2 dir/3.go b/part_7/7.2 dir/3.go new file mode 100644 index 0000000..1fb6f5a --- /dev/null +++ b/part_7/7.2 dir/3.go @@ -0,0 +1,48 @@ +package main + +import ( + "fmt" + "log" + "os" + "path/filepath" +) + +const tempFileName = "myTempFile.dat" +const tempDirName = "myTempDir" + +func printPath(path string, err error) string { + if err != nil { + log.Fatal(err) + } + fmt.Println("TempDir created with path: ", path) + return path +} + +func createdFile(path string) { + filepath := filepath.Join(path, tempFileName) + myFile, err := os.Create(filepath) + if err != nil { + log.Fatal(err) + } + defer myFile.Close() + fmt.Println("TempFile created with path: ", filepath) + fmt.Println() + +} + +func main() { + os.Mkdir(tempDirName, 0777) + + path := printPath(os.MkdirTemp(tempDirName, "*")) // случайное имя временного каталога + createdFile(path) + + path = printPath(os.MkdirTemp(tempDirName, "temp*dir")) // имя с использованием шаблона + createdFile(path) + + path = printPath(os.MkdirTemp(tempDirName, "tempdir")) // имя с использованием шаблона + createdFile(path) + // создание временного каталога со случайным именем + // в системной директории для временных файлов + path = printPath(os.MkdirTemp("", "*")) + createdFile(path) +} diff --git a/part_7/7.2 dir/4.go b/part_7/7.2 dir/4.go new file mode 100644 index 0000000..b591fba --- /dev/null +++ b/part_7/7.2 dir/4.go @@ -0,0 +1,62 @@ +package main + +import ( + "fmt" + "log" + "os" + "path/filepath" +) + +const tempFileName = "myTempFile.dat" +const tempDirName = "myTempDir" + +func printPath(path string, err error) string { + if err != nil { + log.Fatal(err) + } + fmt.Println("TempDir created with path: ", path) + return path +} + +func createdFile(path string) { + filepath := filepath.Join(path, tempFileName) + myFile, err := os.Create(filepath) + if err != nil { + log.Fatal(err) + } + defer myFile.Close() + fmt.Println("TempFile created with path: ", filepath) + fmt.Println() + +} +func deleteTempDir(tempDirSlice []string) { + for _, it := range tempDirSlice { + os.RemoveAll(it) + fmt.Println("TempDir with path:", it, "deleted") + } +} + +func main() { + tempDirSlice := []string{} + + os.Mkdir(tempDirName, 0777) + + path := printPath(os.MkdirTemp(tempDirName, "*")) // случайное имя временного каталога + createdFile(path) + tempDirSlice = append(tempDirSlice, path) + + path = printPath(os.MkdirTemp(tempDirName, "temp*dir")) // имя с использованием шаблона + createdFile(path) + tempDirSlice = append(tempDirSlice, path) + + path = printPath(os.MkdirTemp(tempDirName, "tempdir")) // имя с использованием шаблона + createdFile(path) + tempDirSlice = append(tempDirSlice, path) + // создание временного каталога со случайным именем + // в системной директории для временных файлов + path = printPath(os.MkdirTemp("", "*")) + createdFile(path) + tempDirSlice = append(tempDirSlice, path) + + deleteTempDir(tempDirSlice) // удаление всех временных каталогов +} diff --git a/part_7/7.2 dir/5.go b/part_7/7.2 dir/5.go new file mode 100644 index 0000000..0840214 --- /dev/null +++ b/part_7/7.2 dir/5.go @@ -0,0 +1,26 @@ +package main + +import ( + "fmt" + "log" + "os" + "path/filepath" +) + +const tempFileName = "myTempFile.dat" + +func createdFile(path string) { + filepath := filepath.Join(path, tempFileName) + myFile, err := os.Create(filepath) + if err != nil { + log.Fatal(err) + } + defer myFile.Close() + fmt.Println("File created with path: ", filepath) +} + +func main() { + path := filepath.Join("firstDir", "secondDir", "new") + os.MkdirAll(path, 0777) + createdFile(path) +} diff --git a/part_7/7.2 dir/6.go b/part_7/7.2 dir/6.go new file mode 100644 index 0000000..464a404 --- /dev/null +++ b/part_7/7.2 dir/6.go @@ -0,0 +1,26 @@ +package main + +import ( + "fmt" + "log" + "os" + "path/filepath" +) + +func main() { + path := "C:\\Go" // целевая директория + files, err := os.ReadDir(path) // тип возвращаемого значения - []fs.FileInfo + if err != nil { + log.Fatal(err) + } + + for _, file := range files { + if file.IsDir() { + fmt.Printf("%s is directory. Path: %v\n", + file.Name(), filepath.Join(path, file.Name())) + } else { + fmt.Printf("%s is file. Path: %v\n", + file.Name(), filepath.Join(path, file.Name())) + } + } +} diff --git a/part_7/7.2 dir/7.go b/part_7/7.2 dir/7.go new file mode 100644 index 0000000..c218017 --- /dev/null +++ b/part_7/7.2 dir/7.go @@ -0,0 +1,16 @@ +package main + +import ( + "fmt" + "log" + "os" +) + +func main() { + path, err := os.Getwd() + if err != nil { + log.Fatal(err) + } + + fmt.Println(path) // e:\code\golang\directory +} diff --git a/part_7/7.2 dir/8.go b/part_7/7.2 dir/8.go new file mode 100644 index 0000000..ac3aa72 --- /dev/null +++ b/part_7/7.2 dir/8.go @@ -0,0 +1,27 @@ +package main + +import ( + "fmt" + "log" + "os" +) + +func getWD() { + path, err := os.Getwd() + if err != nil { + log.Fatal(err) + } + fmt.Println("Current path:", path) +} + +func main() { + getWD() + os.Mkdir("myDir", 0777) + os.Chdir("./myDir") + getWD() + myFile, err := os.Create("test.dat") + if err != nil { + log.Fatal(err) + } + defer myFile.Close() +} diff --git a/part_7/7.2 dir/9.go b/part_7/7.2 dir/9.go new file mode 100644 index 0000000..69377a5 --- /dev/null +++ b/part_7/7.2 dir/9.go @@ -0,0 +1,21 @@ +package main + +import ( + "fmt" + "log" + "os" +) + +func getWD() { + path, err := os.Getwd() + if err != nil { + log.Fatal(err) + } + fmt.Println("Current path:", path) +} + +func main() { + getWD() + os.Chdir("../") + getWD() +} diff --git a/part_7/7.3 json/1.go b/part_7/7.3 json/1.go new file mode 100644 index 0000000..624bb10 --- /dev/null +++ b/part_7/7.3 json/1.go @@ -0,0 +1,36 @@ +package main + +import ( + "encoding/json" + "fmt" + "log" +) + +type Student struct { + Name string + Age uint8 + Course uint8 + Single bool + Description []string +} + +func main() { + student := &Student{ + Name: "Alex", + Age: 20, + Course: 2, + Single: true, + Description: []string{ + "Мечтатель", + "Ленив", + "Студент", + "Постоянно жалуется на жизнь", + }, + } + + data, err := json.Marshal(student) + if err != nil { + log.Fatal(err) + } + fmt.Println(string(data)) +} diff --git a/part_7/7.3 json/2.go b/part_7/7.3 json/2.go new file mode 100644 index 0000000..72317e2 --- /dev/null +++ b/part_7/7.3 json/2.go @@ -0,0 +1,38 @@ +package main + +import ( + "encoding/json" + "log" + "os" +) + +type Student struct { + Name string + Age uint8 + Course uint8 + Single bool + Description []string +} + +func main() { + student := &Student{ + Name: "Alex", + Age: 20, + Course: 2, + Single: true, + Description: []string{ + "Мечтатель", + "Ленив", + "Студент", + "Постоянно жалуется на жизнь", + }, + } + + data, err := json.Marshal(student) + myFile, err := os.Create("student.json") + if err != nil { + log.Fatal(err) + } + myFile.Write(data) + defer myFile.Close() +} diff --git a/part_7/7.3 json/3.go b/part_7/7.3 json/3.go new file mode 100644 index 0000000..5ec82c4 --- /dev/null +++ b/part_7/7.3 json/3.go @@ -0,0 +1,31 @@ +package main + +import ( + "encoding/json" + "fmt" + "log" + "os" +) + +type Student struct { + Name string + Age uint8 + Course uint8 + Single bool + Description []string +} + +func main() { + student := &Student{} + + data, err := os.ReadFile("student.json") + if err != nil { + log.Fatal(err) + } + + err = json.Unmarshal(data, student) + if err != nil { + log.Fatal(err) + } + fmt.Printf("%+v", *student) +} diff --git a/part_7/7.3 json/4.go b/part_7/7.3 json/4.go new file mode 100644 index 0000000..b771c61 --- /dev/null +++ b/part_7/7.3 json/4.go @@ -0,0 +1,36 @@ +package main + +import ( + "encoding/json" + "fmt" + "log" +) + +type Student struct { + Name string `json:"name"` // имя поля при сериализации/десериализации + Age uint8 `json:"age"` + Course uint8 `json:"course"` + Single bool `json:"isSingle"` // имя тега может отличаться от имени поля структуры + Description []string `json:"description"` +} + +func main() { + student := &Student{ + Name: "Alex", + Age: 20, + Course: 2, + Single: true, + Description: []string{ + "Мечтатель", + "Ленив", + "Студент", + "Постоянно жалуется на жизнь", + }, + } + + data, err := json.MarshalIndent(student, "", " ") + if err != nil { + log.Fatal(err) + } + fmt.Println(string(data)) +} diff --git a/part_7/7.3 json/5.go b/part_7/7.3 json/5.go new file mode 100644 index 0000000..dbabb28 --- /dev/null +++ b/part_7/7.3 json/5.go @@ -0,0 +1,36 @@ +package main + +import ( + "encoding/json" + "fmt" + "log" +) + +type Student struct { + Name string `json:"name"` // имя поля при сериализации/десериализации + Age uint8 `json:"-"` // поле не должно учитываться + Course uint8 `json:"-"` + Single bool `json:"-"` + Description []string `json:"description"` +} + +func main() { + student := &Student{ + Name: "Alex", + Age: 20, + Course: 2, + Single: true, + Description: []string{ + "Мечтатель", + "Ленив", + "Студент", + "Постоянно жалуется на жизнь", + }, + } + + data, err := json.MarshalIndent(student, "", " ") + if err != nil { + log.Fatal(err) + } + fmt.Println(string(data)) +} diff --git a/part_7/7.3 json/6.go b/part_7/7.3 json/6.go new file mode 100644 index 0000000..81f1f3a --- /dev/null +++ b/part_7/7.3 json/6.go @@ -0,0 +1,81 @@ +package main + +import ( + "encoding/json" + "fmt" + "log" + "os" +) + +type Student struct { + Name string `json:"name"` + Age uint8 `json:"age"` + Course uint8 `json:"course"` + Single bool `json:"isSingle"` + Description []string `json:"description"` +} + +type Group struct { + GroupName string `json:"groupName"` + Course uint8 `json:"course"` + AmountStudents uint8 `json:"amountStudents"` + Students []Student `json:"students"` +} + +func main() { + students := []Student{ + { + Name: "Alex", + Age: 20, + Course: 2, + Single: true, + Description: []string{ + "Мечтатель", + "Ленив", + "Постоянно жалуется на жизнь", + }, + }, + { + Name: "Max", + Age: 16, + Course: 2, + Single: true, + Description: []string{ + "Реалист", + "Мега-мозг", + }, + }, + { + Name: "Smith", + Age: 20, + Course: 2, + Single: false, + Description: []string{ + "Паникер", + "Двоечник", + "Девиз: жизнь - боль...", + }, + }, + } + + group := Group{ + GroupName: "4646M1", + Course: 2, + AmountStudents: uint8(len(students)), + Students: students, + } + + data, err := json.MarshalIndent(&group, "", " ") + if err != nil { + log.Fatal(err) + } + fmt.Println(string(data)) + + myFile, err := os.Create("group.json") + if err != nil { + log.Fatal(err) + } + myFile.Write(data) + defer myFile.Close() + +} diff --git a/part_7/7.3 json/7.go b/part_7/7.3 json/7.go new file mode 100644 index 0000000..26a991b --- /dev/null +++ b/part_7/7.3 json/7.go @@ -0,0 +1,38 @@ +package main + +import ( + "encoding/json" + "fmt" + "log" + "os" +) + +type Student struct { + Name string `json:"name"` + Age uint8 `json:"age"` + Course uint8 `json:"course"` + Single bool `json:"isSingle"` + Description []string `json:"description"` +} + +type Group struct { + GroupName string `json:"groupName"` + Course uint8 `json:"course"` + AmountStudents uint8 `json:"amountStudents"` + Students []Student `json:"students"` +} + +func main() { + group := Group{} + + data, err := os.ReadFile("group.json") + if err != nil { + log.Fatal(err) + } + + err = json.Unmarshal(data, &group) + if err != nil { + log.Fatal(err) + } + fmt.Printf("%+v", group) +} diff --git a/part_7/7.3 json/8.go b/part_7/7.3 json/8.go new file mode 100644 index 0000000..ac84031 --- /dev/null +++ b/part_7/7.3 json/8.go @@ -0,0 +1,38 @@ +package main + +import ( + "encoding/json" + "fmt" + "log" + "os" +) + +type Student struct { + Name string `json:"name"` + Age uint8 `json:"age"` + Course uint8 `json:"course"` + Single bool `json:"isSingle"` + Description []string `json:"description"` +} + +type Group struct { + GroupName string `json:"groupName"` + Course uint8 `json:"course"` + AmountStudents uint8 `json:"amountStudents"` + Students []Student `json:"students"` +} + +func main() { + group := map[string]any{} + + data, err := os.ReadFile("group.json") + if err != nil { + log.Fatal(err) + } + + err = json.Unmarshal(data, &group) + if err != nil { + log.Fatal(err) + } + fmt.Printf("%+v", group) +} diff --git a/part_8/8.1/golang/todo/.vscode/launch.json b/part_8/8.1/golang/todo/.vscode/launch.json new file mode 100644 index 0000000..87f8444 --- /dev/null +++ b/part_8/8.1/golang/todo/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Go App", + "type": "go", + "request": "launch", + "mode": "debug", + "program": "${workspaceFolder}", + "console": "integratedTerminal" + } + ] +} \ No newline at end of file diff --git a/part_8/8.1/golang/todo/db/db.go b/part_8/8.1/golang/todo/db/db.go new file mode 100644 index 0000000..87176c4 --- /dev/null +++ b/part_8/8.1/golang/todo/db/db.go @@ -0,0 +1,94 @@ +package db + +import ( + "database/sql" + "fmt" + "log" + "os" +) + +type SQLiteRepository struct { + db *sql.DB +} + +func createDB(pathToDB string) *sql.DB { + db, err := sql.Open("sqlite3", dbName) + if err != nil { + log.Fatal(err) + } + db.Exec(ProjectTabelDefinition) + db.Exec(TaskTabelDefinition) + return db +} + +func NewSQLiteRepository() *SQLiteRepository { + var db *sql.DB + + if _, err := os.Stat(dbName); os.IsNotExist(err) { + db = createDB(dbName) + fmt.Println("DB isn't exist") + putDefaultValuesToDB(&SQLiteRepository{ + db: db, + }) + } else { + db, err = sql.Open("sqlite3", dbName) + if err != nil { + log.Fatal(err) + } + fmt.Println("DB already exists") + } + + return &SQLiteRepository{ + db: db, + } +} + +func putDefaultValuesToDB(rep *SQLiteRepository) { + firstProject, _ := rep.AddProject(Project{ + Name: "Go", + Description: "Roadmap for learning Go", + }) + secondProject, _ := rep.AddProject(Project{ + Name: "One Year", + Description: "Tasks for the year", + }) + rep.AddTask(Task{ + Name: "Variable", + Description: "Learning Go build-in variables", + Priority: 1, + }, firstProject.ID) + rep.AddTask(Task{ + Name: "Struct", + Description: "Learning use struct in OOP code", + Priority: 3, + }, firstProject.ID) + rep.AddTask(Task{ + Name: "Goroutine", + Description: "Learning concurrent programming", + Priority: 5, + }, firstProject.ID) + rep.AddTask(Task{ + Name: "DataBase", + Description: "How write app with db", + Priority: 1, + }, firstProject.ID) + rep.AddTask(Task{ + Name: "PhD", + Description: "Ph.D. in Technical Sciences", + Priority: 5, + }, secondProject.ID) + rep.AddTask(Task{ + Name: "Losing weight", + Description: "Exercise and eat less chocolate", + Priority: 2, + }, secondProject.ID) + rep.AddTask(Task{ + Name: "Пафос и превозмогание", + Description: "10к подписчиков на канале", + Priority: 2, + }, secondProject.ID) +} + +func (s *SQLiteRepository) Close() { + s.db.Close() +} diff --git a/part_8/8.1/golang/todo/db/db_definition.go b/part_8/8.1/golang/todo/db/db_definition.go new file mode 100644 index 0000000..eb20ce2 --- /dev/null +++ b/part_8/8.1/golang/todo/db/db_definition.go @@ -0,0 +1,31 @@ +package db + +import "errors" + +const dbName = "todo.db" + +var ( + ErrDuplicate = errors.New("record already exists") + ErrNotExists = errors.New("row not exists") + ErrUpdateFailed = errors.New("update failed") + ErrDeleteFailed = errors.New("delete failed") +) + +const ProjectTabelDefinition = ` +CREATE TABLE IF NOT EXISTS projects( + id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + name TEXT UNIQUE, + description TEXT +); +` + +const TaskTabelDefinition = ` +CREATE TABLE IF NOT EXISTS tasks( + id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + name TEXT NOT NULL, + description TEXT NOT NULL, + priority INTEGER NOT NULL, + is_done BOOLEAN NOT NULL CHECK (is_done IN (0, 1)), + project_id INTEGER not null references projects(id) +); +` diff --git a/part_8/8.1/golang/todo/db/models.go b/part_8/8.1/golang/todo/db/models.go new file mode 100644 index 0000000..13bf319 --- /dev/null +++ b/part_8/8.1/golang/todo/db/models.go @@ -0,0 +1,20 @@ +package db + +type Project struct { + ID int + Name string + Description string +} + +type Task struct { + ID int + Name string + Description string + Priority uint8 + IsDone bool +} + +type ProjectTask struct { + Task + ProjectID int +} diff --git a/part_8/8.1/golang/todo/db/projects_crud.go b/part_8/8.1/golang/todo/db/projects_crud.go new file mode 100644 index 0000000..ea382fa --- /dev/null +++ b/part_8/8.1/golang/todo/db/projects_crud.go @@ -0,0 +1,68 @@ +package db + +import ( + "errors" + + "github.com/mattn/go-sqlite3" +) + +func (s *SQLiteRepository) AddProject(project Project) (*Project, error) { + res, err := s.db.Exec("INSERT INTO projects(name, description) values(?,?)", + project.Name, project.Description) + if err != nil { + var sqliteErr sqlite3.Error + if errors.As(err, &sqliteErr) { + if errors.Is(sqliteErr.ExtendedCode, sqlite3.ErrConstraintUnique) { + return nil, ErrDuplicate + } + } + return nil, err + } + + id, err := res.LastInsertId() + if err != nil { + return nil, err + } + project.ID = int(id) + + return &project, nil +} + +func (s *SQLiteRepository) DeleteProject(projectID int) error { + s.db.Exec("DELETE FROM projects WHERE id = ?", projectID) + res, err := s.db.Exec("DELETE FROM tasks WHERE project_id = ?", projectID) + if err != nil { + return err + } + + rowsAffected, err := res.RowsAffected() + // RowsAffected returns the number of rows affected by an update, insert, or delete. + // Not every database or database driver may support this. + if err != nil { + return err + } + + if rowsAffected == 0 { + return ErrDeleteFailed + } + + return err +} + +func (s *SQLiteRepository) GetAllProjects() ([]Project, error) { + rows, err := s.db.Query("SELECT * FROM projects") + if err != nil { + return nil, err + } + defer rows.Close() + + var projects []Project + for rows.Next() { + var project Project + if err := rows.Scan(&project.ID, &project.Name, &project.Description); err != nil { + return nil, err + } + projects = append(projects, project) + } + return projects, nil +} diff --git a/part_8/8.1/golang/todo/db/tasks_crud.go b/part_8/8.1/golang/todo/db/tasks_crud.go new file mode 100644 index 0000000..6df9cc6 --- /dev/null +++ b/part_8/8.1/golang/todo/db/tasks_crud.go @@ -0,0 +1,96 @@ +package db + +import "errors" + +func (s *SQLiteRepository) AddTask(task Task, projectID int) (*Task, error) { + res, err := s.db.Exec("INSERT INTO tasks(name, description, priority, is_done, project_id) values(?,?,?,?,?)", + task.Name, task.Description, task.Priority, task.IsDone, projectID) + if err != nil { + return nil, err + } + + id, err := res.LastInsertId() + if err != nil { + return nil, err + } + task.ID = int(id) + + return &task, nil +} + +func (s *SQLiteRepository) DeleteTask(taskID int) error { + res, err := s.db.Exec("DELETE FROM tasks WHERE id = ?", taskID) + if err != nil { + return err + } + + rowsAffected, err := res.RowsAffected() + // RowsAffected returns the number of rows affected by an update, insert, or delete. + // Not every database or database driver may support this. + if err != nil { + return err + } + + if rowsAffected == 0 { + return ErrDeleteFailed + } + + return err +} + +func (s *SQLiteRepository) GetAllTasks() (tasks []ProjectTask, err error) { + rows, err := s.db.Query("SELECT * FROM tasks") + if err != nil { + return nil, err + } + defer rows.Close() + + for rows.Next() { + var task ProjectTask + if err := rows.Scan(&task.ID, &task.Name, &task.Description, &task.Priority, + &task.IsDone, &task.ProjectID); err != nil { + return nil, err + } + tasks = append(tasks, task) + } + return +} + +func (s *SQLiteRepository) GetProjectTasks(projectID int) (tasks []Task, err error) { + rows, err := s.db.Query("SELECT * FROM tasks WHERE project_id = ?", projectID) + if err != nil { + return nil, err + } + defer rows.Close() + + for rows.Next() { + var task Task + var progID int + if err := rows.Scan(&task.ID, &task.Name, &task.Description, + &task.Priority, &task.IsDone, &progID); err != nil { + return nil, err + } + tasks = append(tasks, task) + } + return +} + +func (s *SQLiteRepository) TaskDone(taskId int) error { + if taskId == 0 { + return errors.New("invalid updated ID") + } + res, err := s.db.Exec("UPDATE tasks SET is_done = ? WHERE id = ?", 1, taskId) + if err != nil { + return err + } + rowsAffected, err := res.RowsAffected() + if err != nil { + return err + } + + if rowsAffected == 0 { + return ErrUpdateFailed + } + + return nil +} diff --git a/part_8/8.1/golang/todo/go.mod b/part_8/8.1/golang/todo/go.mod new file mode 100644 index 0000000..3843df9 --- /dev/null +++ b/part_8/8.1/golang/todo/go.mod @@ -0,0 +1,12 @@ +module golang/todo + +go 1.24 + +require ( + github.com/daviddengcn/go-colortext v1.0.0 // indirect + github.com/dixonwille/wmenu v4.0.2+incompatible // indirect + github.com/mattn/go-isatty v0.0.14 // indirect + github.com/mattn/go-sqlite3 v1.14.24 // indirect + golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect + gopkg.in/dixonwille/wlog.v2 v2.0.0 // indirect +) diff --git a/part_8/8.1/golang/todo/go.sum b/part_8/8.1/golang/todo/go.sum new file mode 100644 index 0000000..80085bc --- /dev/null +++ b/part_8/8.1/golang/todo/go.sum @@ -0,0 +1,17 @@ +github.com/daviddengcn/go-colortext v1.0.0 h1:ANqDyC0ys6qCSvuEK7l3g5RaehL/Xck9EX8ATG8oKsE= +github.com/daviddengcn/go-colortext v1.0.0/go.mod h1:zDqEI5NVUop5QPpVJUxE9UO10hRnmkD5G4Pmri9+m4c= +github.com/dixonwille/wmenu v4.0.2+incompatible h1:lxrPJsx9LpdUFD5T+dOfl6gPKLbBmiAtEdACLT1I2/w= +github.com/dixonwille/wmenu v4.0.2+incompatible/go.mod h1:DnajdZEKFQksxBctWekpWaQXQrDUHRBco6b8MyZnR1s= +github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho= +github.com/golangplus/bytes v1.0.0/go.mod h1:AdRaCFwmc/00ZzELMWb01soso6W1R/++O1XL80yAn+A= +github.com/golangplus/fmt v1.0.0/go.mod h1:zpM0OfbMCjPtd2qkTD/jX2MgiFCqklhSUFyDW44gVQE= +github.com/golangplus/testing v1.0.0/go.mod h1:ZDreixUV3YzhoVraIDyOzHrr76p6NUh6k/pPg/Q3gYA= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-sqlite3 v1.14.13/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= +github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/dixonwille/wlog.v2 v2.0.0 h1:TbGWtD8ahWVSihKKr+z2Dw7Cv/7IrfN6dwrcrre17pU= +gopkg.in/dixonwille/wlog.v2 v2.0.0/go.mod h1:JYQHRnhGPLno/iATOiGkEXoRanJXqdz9Qo6/QwfARUc= diff --git a/part_8/8.1/golang/todo/main.go b/part_8/8.1/golang/todo/main.go new file mode 100644 index 0000000..5b2c4a6 --- /dev/null +++ b/part_8/8.1/golang/todo/main.go @@ -0,0 +1,16 @@ +package main + +import ( + "golang/todo/db" + "golang/todo/menu" + "time" +) + +func main() { + rep := db.NewSQLiteRepository() + defer rep.Close() + for { + menu.CreateMenu(rep) + time.Sleep(2 * time.Second) + } +} diff --git a/part_8/8.1/golang/todo/menu/menu.go b/part_8/8.1/golang/todo/menu/menu.go new file mode 100644 index 0000000..d74d0b6 --- /dev/null +++ b/part_8/8.1/golang/todo/menu/menu.go @@ -0,0 +1,90 @@ +package menu + +import ( + "bufio" + "fmt" + "golang/todo/db" + "log" + "os" + "strconv" + "strings" + + "github.com/dixonwille/wmenu" +) + +func CreateMenu(rep *db.SQLiteRepository) { + menu := wmenu.NewMenu("What would you like to do?") + + menu.Action(func(opts []wmenu.Opt) error { handleFunc(rep, opts); return nil }) + + menu.Option("Add a new Project", 0, false, nil) + menu.Option("Delete a Project by ID", 1, false, nil) + menu.Option("Get all Projects", 2, false, nil) + menu.Option("Add a Task", 3, false, nil) + menu.Option("Get all Tasks", 4, true, nil) // выбор по умолчанию + menu.Option("Get all Project tasks", 5, false, nil) + menu.Option("Done a Task by ID", 6, false, nil) + menu.Option("Delete a Task by ID", 7, false, nil) + menu.Option("Quit Application", 8, false, nil) + menuerr := menu.Run() + fmt.Println() + fmt.Println("---------------------------------") + if menuerr != nil { + log.Fatal(menuerr) + } +} + +func handleFunc(rep *db.SQLiteRepository, opts []wmenu.Opt) { + switch opts[0].Value { + case 0: + fmt.Println("Adding a new Project") + addProject(rep) + case 1: + fmt.Println("Deleting a Project by ID") + deleteProjectByID(rep) + case 2: + fmt.Println("Getting all Projects") + getAllProjects(rep) + case 3: + fmt.Println("Adding a new Task") + addTask(rep) + case 4: + fmt.Println("Getting all Tasks") + getAllTasks(rep) + case 5: + fmt.Println("Getting all Project tasks by ProjectID") + getAllProjectTasks(rep) + case 6: + fmt.Println("Doing a Task by ID") + doneTask(rep) + case 7: + fmt.Println("Deleting a Task by ID") + deleteTaskByID(rep) + case 8: + fmt.Println("See you later!!!") + os.Exit(0) + } +} + +func printNotValidData() { + fmt.Println("Data is not valid!!!") +} + +func getIntValueFromStd(reader *bufio.Reader) (int, error) { + tempID, _, _ := reader.ReadLine() + idStr := strings.TrimSuffix(string(tempID), "\n") + idProj, err := strconv.Atoi(idStr) + if err != nil { + return 0, err + } + return idProj, nil +} + +func getStringValueFromStd(reader *bufio.Reader) (string, error) { + data, err := reader.ReadString('\n') + data = strings.TrimSuffix(data, "\r\n") + if err != nil { + return "", err + } + return data, nil +} diff --git a/part_8/8.1/golang/todo/menu/project_handlers.go b/part_8/8.1/golang/todo/menu/project_handlers.go new file mode 100644 index 0000000..71d116a --- /dev/null +++ b/part_8/8.1/golang/todo/menu/project_handlers.go @@ -0,0 +1,65 @@ +package menu + +import ( + "bufio" + "fmt" + "golang/todo/db" + "os" +) + +func addProject(rep *db.SQLiteRepository) { + project := db.Project{} + reader := bufio.NewReader(os.Stdin) + + fmt.Print("Input project name: ") + name, _ := getStringValueFromStd(reader) + + fmt.Print("Input description project: ") + desc, _ := getStringValueFromStd(reader) + + project.Name = name + project.Description = desc + if project.Name != "" && project.Description != "" { + project, err := rep.AddProject(project) + if err != nil { + fmt.Println(err) + } else { + fmt.Printf("\nAdded project: %+v\n", *project) + } + } else { + printNotValidData() + } +} + +func deleteProjectByID(rep *db.SQLiteRepository) { + fmt.Print("Input ID for deleting project: ") + id, err := getIntValueFromStd(bufio.NewReader(os.Stdin)) + if err != nil { + printNotValidData() + return + } + + err = rep.DeleteProject(id) + if err != nil { + fmt.Println(err) + return + } + fmt.Println("Project deleted") +} + +func getAllProjects(rep *db.SQLiteRepository) { + progects, err := rep.GetAllProjects() + if err != nil { + printNotValidData() + return + } + if len(progects) == 0 { + fmt.Println("You don't have any project") + } else { + fmt.Println("You current projects:") + for _, it := range progects { + fmt.Printf("ProjectID: %v || Name: %v || Desc: %v\n", + it.ID, it.Name, it.Description) + } + } +} diff --git a/part_8/8.1/golang/todo/menu/task_handlers.go b/part_8/8.1/golang/todo/menu/task_handlers.go new file mode 100644 index 0000000..b2d1673 --- /dev/null +++ b/part_8/8.1/golang/todo/menu/task_handlers.go @@ -0,0 +1,122 @@ +package menu + +import ( + "bufio" + "fmt" + "golang/todo/db" + "os" +) + +func addTask(rep *db.SQLiteRepository) { + task := db.Task{} + reader := bufio.NewReader(os.Stdin) + + fmt.Print("Input project ID: ") + projectID, err := getIntValueFromStd(reader) + if err != nil { + printNotValidData() + return + } + + fmt.Print("Input task name: ") + name, _ := getStringValueFromStd(reader) + + fmt.Print("Input description task: ") + desc, _ := getStringValueFromStd(reader) + + fmt.Print("Input priority task: ") + priority, err := getIntValueFromStd(reader) + if err != nil { + printNotValidData() + return + } + + task.Name = name + task.Description = desc + task.Priority = uint8(priority) + if task.Name != "" && task.Description != "" { + task, err := rep.AddTask(task, projectID) + if err != nil { + fmt.Println(err) + } + fmt.Printf("\nAdded task: %+v\n", *task) + } else { + printNotValidData() + } +} + +func deleteTaskByID(rep *db.SQLiteRepository) { + fmt.Print("Input ID for deleting task: ") + id, err := getIntValueFromStd(bufio.NewReader(os.Stdin)) + if err != nil { + printNotValidData() + return + } + + err = rep.DeleteTask(id) + if err != nil { + fmt.Println(err) + return + } + fmt.Println("Task deleted") +} + +func getAllTasks(rep *db.SQLiteRepository) { + tasks, err := rep.GetAllTasks() + if err != nil { + printNotValidData() + return + } + if len(tasks) == 0 { + fmt.Println("You don't have any task") + } else { + fmt.Println("You current tasks: ") + for _, it := range tasks { + fmt.Printf("TaskID: %v || Name: %v || Desc: %v || Priority: %v || IsDone: %v || ProjID: %v\n", + it.ID, it.Name, it.Description, it.Priority, it.IsDone, it.ProjectID) + } + } +} + +func getAllProjectTasks(rep *db.SQLiteRepository) { + fmt.Print("Input ID for project: ") + + id, err := getIntValueFromStd(bufio.NewReader(os.Stdin)) + if err != nil { + printNotValidData() + return + } + + tasks, err := rep.GetProjectTasks(id) + if err != nil { + fmt.Println(err) + return + } + + if len(tasks) == 0 { + fmt.Println("You don't have any task") + } else { + fmt.Printf("Project with ID = %d have next tasks:\n", id) + for _, it := range tasks { + fmt.Printf("TaskID: %v || Name: %v || Desc: %v || Priority: %v || IsDone: %v\n", + it.ID, it.Name, it.Description, it.Priority, it.IsDone) + } + } +} + +func doneTask(rep *db.SQLiteRepository) { + fmt.Print("Input task ID: ") + + id, err := getIntValueFromStd(bufio.NewReader(os.Stdin)) + if err != nil { + printNotValidData() + return + } + + err = rep.TaskDone(id) + if err != nil { + fmt.Println(err) + return + } + fmt.Println("Congratulations! Task done!") +} diff --git a/part_8/8.1/golang/todo/todo.db b/part_8/8.1/golang/todo/todo.db new file mode 100644 index 0000000..efe66a6 Binary files /dev/null and b/part_8/8.1/golang/todo/todo.db differ diff --git a/part_8/8.2/golang/todo_gorm/db/db.go b/part_8/8.2/golang/todo_gorm/db/db.go new file mode 100644 index 0000000..f9ae41a --- /dev/null +++ b/part_8/8.2/golang/todo_gorm/db/db.go @@ -0,0 +1,112 @@ +package db + +import ( + _ "database/sql" + "fmt" + "log" + "os" + + "gorm.io/driver/sqlite" + "gorm.io/gorm" +) + +type SQLiteRepository struct { + db *gorm.DB +} + +func NewSQLiteRepository() *SQLiteRepository { + var db *gorm.DB + + if _, err := os.Stat(dbName); os.IsNotExist(err) { + db, err = gorm.Open(sqlite.Open(dbName), &gorm.Config{}) + if err != nil { + log.Fatal(err) + } + fmt.Println("DB isn't exist") + db.AutoMigrate(&Project{}, &ProjectTask{}) + putDefaultValuesToDB(db) + } else { + db, err = gorm.Open(sqlite.Open(dbName), &gorm.Config{}) + if err != nil { + log.Fatal(err) + } + fmt.Println("DB already exists") + } + + return &SQLiteRepository{ + db: db, + } +} + +func putDefaultValuesToDB(db *gorm.DB) { + firstProject := Project{ + Name: "Go", + Description: "Roadmap for learning Go", + } + secondProject := Project{ + Name: "One Year", + Description: "Tasks for the year", + } + db.Create(&firstProject) + db.Create(&secondProject) + db.Create(&ProjectTask{ + Task: Task{ + Name: "Variable", + Description: "Learning Go build-in variables", + Priority: 1, + }, + Project: &firstProject, + }) + db.Create(&ProjectTask{ + Task: Task{ + Name: "Struct", + Description: "Learning use struct in OOP code", + Priority: 3, + }, + Project: &firstProject, + }) + db.Create(&ProjectTask{ + Task: Task{ + Name: "Goroutine", + Description: "Learning concurrent programming", + Priority: 5, + }, + Project: &firstProject, + }) + db.Create(&ProjectTask{ + Task: Task{ + Name: "DataBase", + Description: "How write app with db", + Priority: 1, + }, + Project: &firstProject, + }) + db.Create(&ProjectTask{ + Task: Task{ + Name: "PhD", + Description: "Ph.D. in Technical Sciences", + Priority: 5, + }, + Project: &secondProject, + }) + db.Create(&ProjectTask{ + Task: Task{ + Name: "Losing weight", + Description: "Exercise and eat less chocolate", + Priority: 2, + }, + Project: &secondProject, + }) + db.Create(&ProjectTask{ + Task: Task{ + Name: "Пафос и превозмогание", + Description: "10к подписчиков на канале", + Priority: 2, + }, + Project: &secondProject, + }) +} + +func (r *SQLiteRepository) Close() { + +} diff --git a/part_8/8.2/golang/todo_gorm/db/db_definition.go b/part_8/8.2/golang/todo_gorm/db/db_definition.go new file mode 100644 index 0000000..d6a42a3 --- /dev/null +++ b/part_8/8.2/golang/todo_gorm/db/db_definition.go @@ -0,0 +1,12 @@ +package db + +import "errors" + +const dbName = "todo.db" + +var ( + ErrDuplicate = errors.New("record already exists") + ErrNotExists = errors.New("row not exists") + ErrUpdateFailed = errors.New("update failed") + ErrDeleteFailed = errors.New("delete failed") +) diff --git a/part_8/8.2/golang/todo_gorm/db/models.go b/part_8/8.2/golang/todo_gorm/db/models.go new file mode 100644 index 0000000..c6c3be6 --- /dev/null +++ b/part_8/8.2/golang/todo_gorm/db/models.go @@ -0,0 +1,21 @@ +package db + +type Project struct { + ID int `gorm:"primary_key;autoIncrement:true;not null"` + Name string `gorm:"unique;not null"` + Description string +} + +type Task struct { + ID int `gorm:"primary_key;autoIncrement;not null"` + Name string `gorm:"not null"` + Description string `gorm:"not null"` + Priority uint8 `gorm:"not null"` + IsDone bool `gorm:"not null"` +} + +type ProjectTask struct { + Task + ProjectID int `gorm:"not null"` + Project *Project `gorm:"foreignKey:ProjectID;references:ID"` +} diff --git a/part_8/8.2/golang/todo_gorm/db/projects_crud.go b/part_8/8.2/golang/todo_gorm/db/projects_crud.go new file mode 100644 index 0000000..5546660 --- /dev/null +++ b/part_8/8.2/golang/todo_gorm/db/projects_crud.go @@ -0,0 +1,49 @@ +package db + +import ( + "errors" + + "github.com/mattn/go-sqlite3" +) + +func (r *SQLiteRepository) AddProject(project Project) (*Project, error) { + tx := r.db.Create(&project) + if tx.Error != nil { + var sqliteErr sqlite3.Error + if errors.As(tx.Error, &sqliteErr) { + if errors.Is(sqliteErr.ExtendedCode, sqlite3.ErrConstraintUnique) { + return nil, ErrDuplicate + } + } + return nil, tx.Error + } + + return &project, nil +} + +func (r *SQLiteRepository) DeleteProject(projectID int) error { + tx := r.db.Delete(&Project{ID: projectID}) + if tx.Error != nil { + return tx.Error + } + + rowsAffected := tx.RowsAffected + if rowsAffected == 0 { + return ErrDeleteFailed + } + + return nil +} + +func (r *SQLiteRepository) GetAllProjects() ([]Project, error) { + var projects []Project + tx := r.db.Find(&projects) + if tx.Error != nil { + return nil, tx.Error + } + if tx.RowsAffected == 0 { + return nil, ErrNotExists + } + + return projects, nil +} diff --git a/part_8/8.2/golang/todo_gorm/db/tasks_crud.go b/part_8/8.2/golang/todo_gorm/db/tasks_crud.go new file mode 100644 index 0000000..61fd340 --- /dev/null +++ b/part_8/8.2/golang/todo_gorm/db/tasks_crud.go @@ -0,0 +1,81 @@ +package db + +import "errors" + +func (r *SQLiteRepository) AddTask(task Task, projectID int) (*Task, error) { + pjTask := &ProjectTask{ + Task: task, + ProjectID: projectID, + } + tx := r.db.Create(pjTask) + if tx.Error != nil { + return nil, tx.Error + } + + return &pjTask.Task, nil +} + +func (r *SQLiteRepository) DeleteTask(taskID int) error { + tx := r.db.Delete(&ProjectTask{Task: Task{ID: taskID}}) + if tx.Error != nil { + return tx.Error + } + + rowsAffected := tx.RowsAffected + if rowsAffected == 0 { + return ErrDeleteFailed + } + + return nil +} + +func (r *SQLiteRepository) GetAllTasks() (tasks []ProjectTask, err error) { + tx := r.db.Find(&tasks) + if tx.Error != nil { + return nil, tx.Error + } + if tx.RowsAffected == 0 { + return nil, ErrNotExists + } + + return +} + +func (r *SQLiteRepository) GetProjectTasks(projectID int) (tasks []Task, err error) { + if projectID == 0 { + return nil, errors.New("invalid updated ID") + } + + var pjTasks []ProjectTask + tx := r.db.Where("project_id", projectID).Find(&pjTasks) + if tx.Error != nil { + return nil, tx.Error + } + if tx.RowsAffected == 0 { + return nil, ErrNotExists + } + + for _, it := range pjTasks { + tasks = append(tasks, it.Task) + } + return +} + +func (r *SQLiteRepository) TaskDone(taskId int) error { + if taskId == 0 { + return errors.New("invalid updated ID") + } + pjTask := &ProjectTask{Task: Task{ID: taskId}} + tx := r.db.Find(&pjTask) + if tx.Error != nil { + return tx.Error + } + pjTask.IsDone = true + r.db.Save(&pjTask) + rowsAffected := tx.RowsAffected + if rowsAffected == 0 { + return ErrUpdateFailed + } + + return nil +} diff --git a/part_8/8.2/golang/todo_gorm/go.mod b/part_8/8.2/golang/todo_gorm/go.mod new file mode 100644 index 0000000..8c00176 --- /dev/null +++ b/part_8/8.2/golang/todo_gorm/go.mod @@ -0,0 +1,21 @@ +module golang/todo + +go 1.24 + +require github.com/dixonwille/wmenu v4.0.2+incompatible + +require ( + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + golang.org/x/text v0.14.0 // indirect +) + +require ( + github.com/daviddengcn/go-colortext v1.0.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-sqlite3 v1.14.24 + golang.org/x/sys v0.6.0 // indirect + gopkg.in/dixonwille/wlog.v2 v2.0.0 // indirect + gorm.io/driver/sqlite v1.5.7 + gorm.io/gorm v1.25.12 +) diff --git a/part_8/8.2/golang/todo_gorm/go.sum b/part_8/8.2/golang/todo_gorm/go.sum new file mode 100644 index 0000000..2823b86 --- /dev/null +++ b/part_8/8.2/golang/todo_gorm/go.sum @@ -0,0 +1,26 @@ +github.com/daviddengcn/go-colortext v1.0.0 h1:ANqDyC0ys6qCSvuEK7l3g5RaehL/Xck9EX8ATG8oKsE= +github.com/daviddengcn/go-colortext v1.0.0/go.mod h1:zDqEI5NVUop5QPpVJUxE9UO10hRnmkD5G4Pmri9+m4c= +github.com/dixonwille/wmenu v4.0.2+incompatible h1:lxrPJsx9LpdUFD5T+dOfl6gPKLbBmiAtEdACLT1I2/w= +github.com/dixonwille/wmenu v4.0.2+incompatible/go.mod h1:DnajdZEKFQksxBctWekpWaQXQrDUHRBco6b8MyZnR1s= +github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho= +github.com/golangplus/bytes v1.0.0/go.mod h1:AdRaCFwmc/00ZzELMWb01soso6W1R/++O1XL80yAn+A= +github.com/golangplus/fmt v1.0.0/go.mod h1:zpM0OfbMCjPtd2qkTD/jX2MgiFCqklhSUFyDW44gVQE= +github.com/golangplus/testing v1.0.0/go.mod h1:ZDreixUV3YzhoVraIDyOzHrr76p6NUh6k/pPg/Q3gYA= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= +github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +gopkg.in/dixonwille/wlog.v2 v2.0.0 h1:TbGWtD8ahWVSihKKr+z2Dw7Cv/7IrfN6dwrcrre17pU= +gopkg.in/dixonwille/wlog.v2 v2.0.0/go.mod h1:JYQHRnhGPLno/iATOiGkEXoRanJXqdz9Qo6/QwfARUc= +gorm.io/driver/sqlite v1.5.7 h1:8NvsrhP0ifM7LX9G4zPB97NwovUakUxc+2V2uuf3Z1I= +gorm.io/driver/sqlite v1.5.7/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4= +gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= +gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= diff --git a/part_8/8.2/golang/todo_gorm/main.go b/part_8/8.2/golang/todo_gorm/main.go new file mode 100644 index 0000000..5b2c4a6 --- /dev/null +++ b/part_8/8.2/golang/todo_gorm/main.go @@ -0,0 +1,16 @@ +package main + +import ( + "golang/todo/db" + "golang/todo/menu" + "time" +) + +func main() { + rep := db.NewSQLiteRepository() + defer rep.Close() + for { + menu.CreateMenu(rep) + time.Sleep(2 * time.Second) + } +} diff --git a/part_8/8.2/golang/todo_gorm/menu/menu.go b/part_8/8.2/golang/todo_gorm/menu/menu.go new file mode 100644 index 0000000..d74d0b6 --- /dev/null +++ b/part_8/8.2/golang/todo_gorm/menu/menu.go @@ -0,0 +1,90 @@ +package menu + +import ( + "bufio" + "fmt" + "golang/todo/db" + "log" + "os" + "strconv" + "strings" + + "github.com/dixonwille/wmenu" +) + +func CreateMenu(rep *db.SQLiteRepository) { + menu := wmenu.NewMenu("What would you like to do?") + + menu.Action(func(opts []wmenu.Opt) error { handleFunc(rep, opts); return nil }) + + menu.Option("Add a new Project", 0, false, nil) + menu.Option("Delete a Project by ID", 1, false, nil) + menu.Option("Get all Projects", 2, false, nil) + menu.Option("Add a Task", 3, false, nil) + menu.Option("Get all Tasks", 4, true, nil) // выбор по умолчанию + menu.Option("Get all Project tasks", 5, false, nil) + menu.Option("Done a Task by ID", 6, false, nil) + menu.Option("Delete a Task by ID", 7, false, nil) + menu.Option("Quit Application", 8, false, nil) + menuerr := menu.Run() + fmt.Println() + fmt.Println("---------------------------------") + if menuerr != nil { + log.Fatal(menuerr) + } +} + +func handleFunc(rep *db.SQLiteRepository, opts []wmenu.Opt) { + switch opts[0].Value { + case 0: + fmt.Println("Adding a new Project") + addProject(rep) + case 1: + fmt.Println("Deleting a Project by ID") + deleteProjectByID(rep) + case 2: + fmt.Println("Getting all Projects") + getAllProjects(rep) + case 3: + fmt.Println("Adding a new Task") + addTask(rep) + case 4: + fmt.Println("Getting all Tasks") + getAllTasks(rep) + case 5: + fmt.Println("Getting all Project tasks by ProjectID") + getAllProjectTasks(rep) + case 6: + fmt.Println("Doing a Task by ID") + doneTask(rep) + case 7: + fmt.Println("Deleting a Task by ID") + deleteTaskByID(rep) + case 8: + fmt.Println("See you later!!!") + os.Exit(0) + } +} + +func printNotValidData() { + fmt.Println("Data is not valid!!!") +} + +func getIntValueFromStd(reader *bufio.Reader) (int, error) { + tempID, _, _ := reader.ReadLine() + idStr := strings.TrimSuffix(string(tempID), "\n") + idProj, err := strconv.Atoi(idStr) + if err != nil { + return 0, err + } + return idProj, nil +} + +func getStringValueFromStd(reader *bufio.Reader) (string, error) { + data, err := reader.ReadString('\n') + data = strings.TrimSuffix(data, "\r\n") + if err != nil { + return "", err + } + return data, nil +} diff --git a/part_8/8.2/golang/todo_gorm/menu/project_handlers.go b/part_8/8.2/golang/todo_gorm/menu/project_handlers.go new file mode 100644 index 0000000..71d116a --- /dev/null +++ b/part_8/8.2/golang/todo_gorm/menu/project_handlers.go @@ -0,0 +1,65 @@ +package menu + +import ( + "bufio" + "fmt" + "golang/todo/db" + "os" +) + +func addProject(rep *db.SQLiteRepository) { + project := db.Project{} + reader := bufio.NewReader(os.Stdin) + + fmt.Print("Input project name: ") + name, _ := getStringValueFromStd(reader) + + fmt.Print("Input description project: ") + desc, _ := getStringValueFromStd(reader) + + project.Name = name + project.Description = desc + if project.Name != "" && project.Description != "" { + project, err := rep.AddProject(project) + if err != nil { + fmt.Println(err) + } else { + fmt.Printf("\nAdded project: %+v\n", *project) + } + } else { + printNotValidData() + } +} + +func deleteProjectByID(rep *db.SQLiteRepository) { + fmt.Print("Input ID for deleting project: ") + id, err := getIntValueFromStd(bufio.NewReader(os.Stdin)) + if err != nil { + printNotValidData() + return + } + + err = rep.DeleteProject(id) + if err != nil { + fmt.Println(err) + return + } + fmt.Println("Project deleted") +} + +func getAllProjects(rep *db.SQLiteRepository) { + progects, err := rep.GetAllProjects() + if err != nil { + printNotValidData() + return + } + if len(progects) == 0 { + fmt.Println("You don't have any project") + } else { + fmt.Println("You current projects:") + for _, it := range progects { + fmt.Printf("ProjectID: %v || Name: %v || Desc: %v\n", + it.ID, it.Name, it.Description) + } + } +} diff --git a/part_8/8.2/golang/todo_gorm/menu/task_handlers.go b/part_8/8.2/golang/todo_gorm/menu/task_handlers.go new file mode 100644 index 0000000..b2d1673 --- /dev/null +++ b/part_8/8.2/golang/todo_gorm/menu/task_handlers.go @@ -0,0 +1,122 @@ +package menu + +import ( + "bufio" + "fmt" + "golang/todo/db" + "os" +) + +func addTask(rep *db.SQLiteRepository) { + task := db.Task{} + reader := bufio.NewReader(os.Stdin) + + fmt.Print("Input project ID: ") + projectID, err := getIntValueFromStd(reader) + if err != nil { + printNotValidData() + return + } + + fmt.Print("Input task name: ") + name, _ := getStringValueFromStd(reader) + + fmt.Print("Input description task: ") + desc, _ := getStringValueFromStd(reader) + + fmt.Print("Input priority task: ") + priority, err := getIntValueFromStd(reader) + if err != nil { + printNotValidData() + return + } + + task.Name = name + task.Description = desc + task.Priority = uint8(priority) + if task.Name != "" && task.Description != "" { + task, err := rep.AddTask(task, projectID) + if err != nil { + fmt.Println(err) + } + fmt.Printf("\nAdded task: %+v\n", *task) + } else { + printNotValidData() + } +} + +func deleteTaskByID(rep *db.SQLiteRepository) { + fmt.Print("Input ID for deleting task: ") + id, err := getIntValueFromStd(bufio.NewReader(os.Stdin)) + if err != nil { + printNotValidData() + return + } + + err = rep.DeleteTask(id) + if err != nil { + fmt.Println(err) + return + } + fmt.Println("Task deleted") +} + +func getAllTasks(rep *db.SQLiteRepository) { + tasks, err := rep.GetAllTasks() + if err != nil { + printNotValidData() + return + } + if len(tasks) == 0 { + fmt.Println("You don't have any task") + } else { + fmt.Println("You current tasks: ") + for _, it := range tasks { + fmt.Printf("TaskID: %v || Name: %v || Desc: %v || Priority: %v || IsDone: %v || ProjID: %v\n", + it.ID, it.Name, it.Description, it.Priority, it.IsDone, it.ProjectID) + } + } +} + +func getAllProjectTasks(rep *db.SQLiteRepository) { + fmt.Print("Input ID for project: ") + + id, err := getIntValueFromStd(bufio.NewReader(os.Stdin)) + if err != nil { + printNotValidData() + return + } + + tasks, err := rep.GetProjectTasks(id) + if err != nil { + fmt.Println(err) + return + } + + if len(tasks) == 0 { + fmt.Println("You don't have any task") + } else { + fmt.Printf("Project with ID = %d have next tasks:\n", id) + for _, it := range tasks { + fmt.Printf("TaskID: %v || Name: %v || Desc: %v || Priority: %v || IsDone: %v\n", + it.ID, it.Name, it.Description, it.Priority, it.IsDone) + } + } +} + +func doneTask(rep *db.SQLiteRepository) { + fmt.Print("Input task ID: ") + + id, err := getIntValueFromStd(bufio.NewReader(os.Stdin)) + if err != nil { + printNotValidData() + return + } + + err = rep.TaskDone(id) + if err != nil { + fmt.Println(err) + return + } + fmt.Println("Congratulations! Task done!") +} diff --git a/part_8/8.2/golang/todo_gorm/todo.db b/part_8/8.2/golang/todo_gorm/todo.db new file mode 100644 index 0000000..a9842cd Binary files /dev/null and b/part_8/8.2/golang/todo_gorm/todo.db differ diff --git a/part_8/8.3/golang/todo_transaction/go.mod b/part_8/8.3/golang/todo_transaction/go.mod new file mode 100644 index 0000000..123b5b0 --- /dev/null +++ b/part_8/8.3/golang/todo_transaction/go.mod @@ -0,0 +1,14 @@ +module golang/todo + +go 1.24 + +require gorm.io/gorm v1.25.12 + +require github.com/mattn/go-sqlite3 v1.14.22 // indirect + +require ( + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + golang.org/x/text v0.14.0 // indirect + gorm.io/driver/sqlite v1.5.7 +) diff --git a/part_8/8.3/golang/todo_transaction/go.sum b/part_8/8.3/golang/todo_transaction/go.sum new file mode 100644 index 0000000..0b0dab8 --- /dev/null +++ b/part_8/8.3/golang/todo_transaction/go.sum @@ -0,0 +1,12 @@ +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +gorm.io/driver/sqlite v1.5.7 h1:8NvsrhP0ifM7LX9G4zPB97NwovUakUxc+2V2uuf3Z1I= +gorm.io/driver/sqlite v1.5.7/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4= +gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= +gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= diff --git a/part_8/8.3/golang/todo_transaction/main.go b/part_8/8.3/golang/todo_transaction/main.go new file mode 100644 index 0000000..5c19a1d --- /dev/null +++ b/part_8/8.3/golang/todo_transaction/main.go @@ -0,0 +1,243 @@ +package main + +import ( + "errors" + "fmt" + "os" + + "gorm.io/driver/sqlite" + "gorm.io/gorm" +) + +const dbName = "todo.db" + +var ErrNotExists = errors.New("row not exists") + +type Project struct { + ID int `gorm:"primary_key;autoIncrement:true;not null"` + Name string `gorm:"unique;not null"` + Description string +} + +type ProjectTask struct { + ID int `gorm:"primary_key;autoIncrement;not null"` + Name string `gorm:"not null"` + Description string `gorm:"not null"` + Priority uint8 `gorm:"not null"` + IsDone bool `gorm:"not null"` + ProjectID int `gorm:"not null"` + Project *Project `gorm:"foreignKey:ProjectID;references:ID"` +} + +func connectionToBD(pathToDB string) (db *gorm.DB, err error) { + if _, err := os.Stat(dbName); os.IsNotExist(err) { + db, err = gorm.Open(sqlite.Open(dbName), &gorm.Config{}) + if err != nil { + return nil, err + } + fmt.Println("DB isn't exist") + db.AutoMigrate(&Project{}, &ProjectTask{}) + putDefaultValuesToDB(db) + } else { + db, err = gorm.Open(sqlite.Open(dbName), &gorm.Config{}) + if err != nil { + return nil, err + } + fmt.Println("DB already exists") + } + return +} + +func putDefaultValuesToDB(db *gorm.DB) { + db.Transaction(func(tx *gorm.DB) error { // начало транзакции + firstProject := Project{ + Name: "Go", + Description: "Roadmap for learning Go", + } + secondProject := Project{ + Name: "One Year", + Description: "Tasks for the year", + } + + tx.Create(&firstProject) + + if err := tx.Create(&secondProject).Error; err != nil { //проверяем на наличие ошибок при записи + return err // вызываем отмену транзакции + } + + tx.Create(&ProjectTask{ + Name: "Variable", + Description: "Learning Go build-in variables", + Priority: 1, + Project: &firstProject, + }) + + if err := tx.Create(&ProjectTask{ //проверяем на наличие ошибок при записи + Name: "Struct", + Description: "Learning use struct in OOP code", + Priority: 3, + Project: &firstProject, + }).Error; err != nil { + return err // вызываем отмену транзакции + } + + tx.Create(&ProjectTask{ + Name: "Goroutine", + Description: "Learning concurrent programming", + Priority: 5, + Project: &firstProject, + }) + tx.Create(&ProjectTask{ + Name: "DataBase", + Description: "How write app with db", + Priority: 1, + Project: &firstProject, + }) + tx.Create(&ProjectTask{ + Name: "PhD", + Description: "Ph.D. in Technical Sciences", + Priority: 5, + Project: &secondProject, + }) + tx.Create(&ProjectTask{ + Name: "Losing weight", + Description: "Exercise and eat less chocolate", + Priority: 2, + Project: &secondProject, + }) + tx.Create(&ProjectTask{ + Name: "Пафос и превозмогание", + Description: "10к подписчиков на канале", + Priority: 2, + Project: &secondProject, + }) + return nil + }) +} + +func GetAllProjects(db *gorm.DB) ([]Project, error) { + var projects []Project + tx := db.Find(&projects) + if tx.Error != nil { + return nil, tx.Error + } + if tx.RowsAffected == 0 { + return nil, ErrNotExists + } + + return projects, nil +} + +func GetAllTasks(db *gorm.DB) (tasks []ProjectTask, err error) { + tx := db.Find(&tasks) + if tx.Error != nil { + return nil, tx.Error + } + if tx.RowsAffected == 0 { + return nil, ErrNotExists + } + + return +} + +func printAllTasks(db *gorm.DB) { + tasks, err := GetAllTasks(db) + if err != nil { + return + } + fmt.Println("*********Tasks*********") + for _, it := range tasks { + fmt.Printf("TaskID: %v || Name: %v || Priority: %v || IsDone: %v || ProjID: %v\n", + it.ID, it.Name, it.Priority, it.IsDone, it.ProjectID) + } +} + +func printAllProjects(db *gorm.DB) { + progects, err := GetAllProjects(db) + if err != nil { + return + } + fmt.Println("*********Projects*********") + for _, it := range progects { + fmt.Printf("ProjectID: %v || Name: %v || Desc: %v\n", + it.ID, it.Name, it.Description) + } +} + +func printAllProjectAndTask(db *gorm.DB) { + printAllProjects(db) + printAllTasks(db) +} + +func GetAllProjectTasks(db *gorm.DB, projectID int) (tasks []ProjectTask, err error) { + tx := db.Where("project_id", projectID).Find(&tasks) + if tx.Error != nil { + return nil, tx.Error + } + if tx.RowsAffected == 0 { + return nil, ErrNotExists + } + + return +} + +func printAllProjectTasks(db *gorm.DB, projectID int) { + tasks, err := GetAllProjectTasks(db, projectID) + if err != nil { + return + } + fmt.Println("*********Tasks*********") + for _, it := range tasks { + fmt.Printf("TaskID: %v || Name: %v || Priority: %v || IsDone: %v || ProjID: %v\n", + it.ID, it.Name, it.Priority, it.IsDone, it.ProjectID) + } +} + +func main() { + db, _ := gorm.Open(sqlite.Open(dbName), &gorm.Config{DryRun: true}) + + var tasks []ProjectTask + stmt := db.Where("project_id", 1).Find(&tasks).Statement + fmt.Println(stmt.SQL.String()) + + stmt = db.Create(&ProjectTask{ + Name: "Пафос и превозмогание", + Description: "10к подписчиков на канале", + Priority: 2, + ProjectID: 2, + }).Statement + fmt.Println(stmt.SQL.String()) + + firstProject := Project{ + Name: "Go", + Description: "Roadmap for learning Go", + } + + stmt = db.Create(&firstProject).Statement + fmt.Println(stmt.SQL.String()) +} + +func CreateProjects(db *gorm.DB) error { + tx := db.Begin() + defer func() { + if r := recover(); r != nil { + tx.Rollback() + } + }() + + if err := tx.Error; err != nil { + return err + } + + if err := tx.Create(&Project{Name: "Oo"}).Error; err != nil { + tx.Rollback() + return err + } + + if err := tx.Create(&Project{Name: "^_^"}).Error; err != nil { + tx.Rollback() + return err + } + + return tx.Commit().Error +} diff --git a/part_8/8.3/golang/todo_transaction/todo.db b/part_8/8.3/golang/todo_transaction/todo.db new file mode 100644 index 0000000..c9f63bd Binary files /dev/null and b/part_8/8.3/golang/todo_transaction/todo.db differ diff --git a/part_9/9.10/fan-in.go b/part_9/9.10/fan-in.go new file mode 100644 index 0000000..ea7bca9 --- /dev/null +++ b/part_9/9.10/fan-in.go @@ -0,0 +1,77 @@ +package main + +import ( + "fmt" + "sync" +) + +type TaskItem struct { + id int +} + +func generateInputs(work *[]TaskItem) (in1, in2 <-chan TaskItem) { + ch1 := make(chan TaskItem) + ch2 := make(chan TaskItem) + + go func() { + defer close(ch1) + defer close(ch2) + + for it, value := range *work { + if it%2 == 0 { + ch1 <- value + } else { + ch2 <- value + } + } + }() + + return ch1, ch2 +} + +func main() { + tasks := []TaskItem{ + {0}, {1}, {2}, + {3}, {4}, {5}, + {6}, {7}, {8}, + {9}, {10}, + } + + in1, in2 := generateInputs(&tasks) + + out := fanIn(in1, in2) + + for value := range out { + fmt.Println("Value:", value) + } + fmt.Println("Finished") +} + +func fanIn(inputs ...<-chan TaskItem) <-chan TaskItem { + var wg sync.WaitGroup + out := make(chan TaskItem) + + wg.Add(len(inputs)) + + for _, in := range inputs { + go func(ch <-chan TaskItem) { + for { + value, ok := <-ch + + if !ok { + wg.Done() + break + } + + out <- value + } + }(in) + } + + go func() { + wg.Wait() + close(out) + }() + + return out +} diff --git a/part_9/9.10/fan-out.go b/part_9/9.10/fan-out.go new file mode 100644 index 0000000..673ea82 --- /dev/null +++ b/part_9/9.10/fan-out.go @@ -0,0 +1,62 @@ +package main + +import ( + "fmt" +) + +type TaskItem struct { + id int +} + +func main() { + tasks := []TaskItem{ + {0}, {1}, {2}, + {3}, {4}, {5}, + {6}, {7}, {8}, + {9}, {10}, + } + + in := generateInput(&tasks) + + out1 := fanOut(in) + out2 := fanOut(in) + out3 := fanOut(in) + + for range tasks { + select { + case value := <-out1: + fmt.Println("Task in output-1: ", value) + case value := <-out2: + fmt.Println("Task in output-2: ", value) + case value := <-out3: + fmt.Println("Task in output-3: ", value) + } + } + fmt.Println("Finished") +} + +func generateInput(work *[]TaskItem) (in1 <-chan TaskItem) { + ch1 := make(chan TaskItem) + go func() { + defer close(ch1) + for _, value := range *work { + ch1 <- value + } + }() + + return ch1 +} + +func fanOut(in <-chan TaskItem) <-chan TaskItem { + out := make(chan TaskItem) + + go func() { + defer close(out) + + for data := range in { + out <- data + } + }() + + return out +} diff --git a/part_9/9.10/generator.go b/part_9/9.10/generator.go new file mode 100644 index 0000000..e38fc53 --- /dev/null +++ b/part_9/9.10/generator.go @@ -0,0 +1,20 @@ +package main + +import "fmt" + +func Generator(start int, end int) <-chan int { + ch := make(chan int, end-start) + go func(ch chan int) { + for i := start; i <= end; i++ { + ch <- i // помещение значения в канал + } + close(ch) + }(ch) + return ch +} + +func main() { + for it := range Generator(1, 10) { + fmt.Printf("%d || ", it) + } +} diff --git a/part_9/9.10/pipeline.go b/part_9/9.10/pipeline.go new file mode 100644 index 0000000..061a5a1 --- /dev/null +++ b/part_9/9.10/pipeline.go @@ -0,0 +1,62 @@ +package main + +import ( + "fmt" + "math" +) + +func main() { + slice := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12} + + out := source(slice) // первый блок конвейера + out = square(out) // блок возведения в квадрат + out = decriment(out) // блок декремента значения + + for value := range out { // вывод результата работы конвейера в терминал + fmt.Printf("%d ", value) + } +} + +func source(in []int) <-chan int { + out := make(chan int) + + go func() { + defer close(out) + for _, it := range in { + if it%3 != 0 { + out <- it + } + } + }() + + return out +} + +func square(in <-chan int) <-chan int { + out := make(chan int) + + go func() { + defer close(out) + + for i := range in { + value := math.Pow(float64(i), 2) + out <- int(value) + } + }() + + return out +} + +func decriment(in <-chan int) <-chan int { + out := make(chan int) + + go func() { + defer close(out) + + for i := range in { + out <- i - 1 + } + }() + + return out +} diff --git a/part_9/9.10/queuing.go b/part_9/9.10/queuing.go new file mode 100644 index 0000000..1122084 --- /dev/null +++ b/part_9/9.10/queuing.go @@ -0,0 +1,44 @@ +package main + +import ( + "fmt" + "sync" + "time" +) + +type TaskItem struct { + id int +} + +func main() { + var wg sync.WaitGroup + limit := make(chan interface{}, 2) + workers := func(l chan<- interface{}, wg *sync.WaitGroup, tasks *[]TaskItem) { + for _, value := range *tasks { + value := value // удалите и посмотрите на вывод в терминал + // не используйте в замыкании передачу задачи по ссылке на переменную value + // объявленную в цикле (_, value := range *tasks) + + limit <- struct{}{} + wg.Add(1) + + go func(workItem *TaskItem, w *sync.WaitGroup) { + defer w.Done() + fmt.Printf("Task %d processing\n", workItem.id) + time.Sleep(1 * time.Second) + <-limit + }(&value, wg) + } + } + + tasks := []TaskItem{ + {0}, {1}, {2}, + {3}, {4}, {5}, + {6}, {7}, {8}, + {9}, + } + workers(limit, &wg, &tasks) + wg.Wait() + + fmt.Println("Finished") +} diff --git a/part_9/9.10/workerpool.go b/part_9/9.10/workerpool.go new file mode 100644 index 0000000..ae33bbc --- /dev/null +++ b/part_9/9.10/workerpool.go @@ -0,0 +1,58 @@ +package main + +import ( + "fmt" + "sync" +) + +const totalElements = 6 +const totalWorkers = 3 + +type TaskItem struct { + id int + data int +} + +func main() { + input := make(chan TaskItem, totalElements) + output := make(chan TaskItem, totalElements) + + for w := 1; w <= totalWorkers; w++ { + go worker(w, input, output) + } + + // Отправка данных для обработки + for j := 0; j < totalElements; j++ { + input <- TaskItem{j, j} + } + + close(input) + + // Работа с результатами + for a := 0; a < totalElements; a++ { + task := <-output + fmt.Printf("Task-%d finished!\n", task.id) + } + + close(output) +} + +func worker(id int, input <-chan TaskItem, output chan<- TaskItem) { + var wg sync.WaitGroup + + for j := range input { + wg.Add(1) + + go func(task TaskItem) { + defer wg.Done() + + fmt.Printf("Worker %d started task %+v\n", id, task) + task.data *= task.data + output <- task + + fmt.Printf("Worker %d finished task %+v\n", id, task) + }(j) + } + + wg.Wait() +} diff --git a/part_9/9.3/1.go b/part_9/9.3/1.go new file mode 100644 index 0000000..b13b244 --- /dev/null +++ b/part_9/9.3/1.go @@ -0,0 +1,18 @@ +package main + +import "fmt" + +func namedGorutine() { + for i := 0; i <= 5; i++ { + fmt.Printf("%d ", i) + } +} + +func main() { + go namedGorutine() // объявление горутины + go func() { + for i := 6; i <= 10; i++ { + fmt.Printf("%d", i) + } + }() +} diff --git a/part_9/9.3/2.go b/part_9/9.3/2.go new file mode 100644 index 0000000..77abd23 --- /dev/null +++ b/part_9/9.3/2.go @@ -0,0 +1,22 @@ +package main + +import ( + "fmt" + "time" +) + +func namedGorutine() { + for i := 0; i <= 5; i++ { + fmt.Printf("%d ", i) + } +} + +func main() { + go namedGorutine() // объявление горутины + go func() { + for i := 6; i <= 10; i++ { + fmt.Printf("%d", i) + } + }() + time.Sleep(time.Second) +} diff --git a/part_9/9.3/3.go b/part_9/9.3/3.go new file mode 100644 index 0000000..dfee768 --- /dev/null +++ b/part_9/9.3/3.go @@ -0,0 +1,17 @@ +package main + +import ( + "fmt" + "time" +) + +func namedGorutine(number int) { + fmt.Printf("%d ", number) +} + +func main() { + for i := 0; i <= 30; i++ { + go namedGorutine(i) + } + time.Sleep(time.Second) +} diff --git a/part_9/9.3/4.go b/part_9/9.3/4.go new file mode 100644 index 0000000..88ac342 --- /dev/null +++ b/part_9/9.3/4.go @@ -0,0 +1,16 @@ +package main + +import ( + "fmt" + "time" +) + +func namedGorutine(number int) int{ + fmt.Printf("%d ", number) + return number +} + +func main() { + number := go namedGorutine(1) + time.Sleep(time.Second) +} diff --git a/part_9/9.4/1.go b/part_9/9.4/1.go new file mode 100644 index 0000000..40f240e --- /dev/null +++ b/part_9/9.4/1.go @@ -0,0 +1,21 @@ +package main + +import ( + "fmt" + "sync" +) + +func namedGorutine(number int, waitGroup *sync.WaitGroup) { + defer waitGroup.Done() // уменьшение счетчика sync.WaitGroup на 1 + fmt.Printf("%d", number) +} + +func main() { + var waitGroup sync.WaitGroup + + for i := 0; i <= 30; i++ { + waitGroup.Add(1) // увеличение счетчика на 1 + go namedGorutine(i, &waitGroup) + } + waitGroup.Wait() // ожидание завершения всех запущенных горутин +} diff --git a/part_9/9.4/2.go b/part_9/9.4/2.go new file mode 100644 index 0000000..ed94015 --- /dev/null +++ b/part_9/9.4/2.go @@ -0,0 +1,26 @@ +package main + +import ( + "fmt" + "sync" +) + +func namedGorutine(number int, waitGroup *sync.WaitGroup) { + defer waitGroup.Done() // уменьшение счетчика sync.WaitGroup на 1 + fmt.Printf("%d ", number) +} + +func main() { + var waitGroup sync.WaitGroup + + waitGroup.Add(1) // приведет к ошибке! + fmt.Printf("%#v\n", waitGroup) + + for i := 0; i <= 30; i++ { + waitGroup.Add(1) // увеличение счетчика на 1 + go namedGorutine(i, &waitGroup) + } + + fmt.Printf("\n%#v\n", waitGroup) + waitGroup.Wait() +} diff --git a/part_9/9.4/3.go b/part_9/9.4/3.go new file mode 100644 index 0000000..7c0c3e3 --- /dev/null +++ b/part_9/9.4/3.go @@ -0,0 +1,26 @@ +package main + +import ( + "fmt" + "sync" +) + +func namedGorutine(number int, waitGroup *sync.WaitGroup) { + defer waitGroup.Done() // уменьшение счетчика sync.WaitGroup на 1 + fmt.Printf("%d ", number) +} + +func main() { + var waitGroup sync.WaitGroup + + fmt.Printf("%#v\n", waitGroup) + waitGroup.Done() // приведет к панике! + for i := 0; i <= 30; i++ { + waitGroup.Add(1) // увеличение счетчика на 1 + go namedGorutine(i, &waitGroup) + + } + + fmt.Printf("\n%#v\n", waitGroup) + waitGroup.Wait() +} diff --git a/part_9/9.5/1.go b/part_9/9.5/1.go new file mode 100644 index 0000000..161b94d --- /dev/null +++ b/part_9/9.5/1.go @@ -0,0 +1,31 @@ +package main + +import ( + "fmt" + "sync" + "time" +) + +var waitGroup sync.WaitGroup + +func myPrint(c chan int) { + value, ok := <-c // чтение из канала. Горутина блокируется до тех пор, + // пока не появятся данные для чтения + if ok { + fmt.Println("Channel is open!") + } else { + fmt.Println("Channel is closed!") + } + fmt.Println(value, ok) + waitGroup.Done() +} + +func main() { + myChannel := make(chan int) // объявление канала из 1-го элемента + defer close(myChannel) // отложенное закрытие канала + go myPrint(myChannel) + waitGroup.Add(1) + time.Sleep(time.Second) + myChannel <- 10 // запись значения 10 в канал + waitGroup.Wait() +} diff --git a/part_9/9.5/10.go b/part_9/9.5/10.go new file mode 100644 index 0000000..0a4dc49 --- /dev/null +++ b/part_9/9.5/10.go @@ -0,0 +1,34 @@ +package main + +import ( + "fmt" + "time" +) + +func main() { + ping := make(chan int, 1) + pong := make(chan int, 1) + + ping <- 1 + + go play(ping, pong) + + time.Sleep(2 * time.Second) + fmt.Println("Exit") +} + +func play(ping, pong chan int) { + var ball int + for { + select { + case ball = <-ping: + fmt.Println("Ping", ball) + time.Sleep(500 * time.Millisecond) + pong <- ball + 1 + case ball = <-pong: + fmt.Println("Pong", ball) + time.Sleep(500 * time.Millisecond) + ping <- ball + 1 + } + } +} diff --git a/part_9/9.5/11.go b/part_9/9.5/11.go new file mode 100644 index 0000000..f15be56 --- /dev/null +++ b/part_9/9.5/11.go @@ -0,0 +1,35 @@ +package main + +import ( + "fmt" + "time" +) + +func main() { + ping := make(chan int, 1) + pong := make(chan int, 1) + + // ping <- 1 + + go func(ping, pong chan int) { + var ball int + for { + select { + case ball = <-ping: + fmt.Println("Ping", ball) + time.Sleep(500 * time.Millisecond) + pong <- ball + 1 + case ball = <-pong: + fmt.Println("Pong", ball) + time.Sleep(500 * time.Millisecond) + ping <- ball + 1 + case value := <-time.After(time.Second): + fmt.Println("Time out!!!", value) + return + } + } + }(ping, pong) + + time.Sleep(4 * time.Second) + fmt.Println("Exit") +} diff --git a/part_9/9.5/12.go b/part_9/9.5/12.go new file mode 100644 index 0000000..ad8b2bf --- /dev/null +++ b/part_9/9.5/12.go @@ -0,0 +1,35 @@ +package main + +import ( + "fmt" + "time" +) + +func main() { + ping := make(chan int, 1) + pong := make(chan int, 1) + + // ping <- 1 + + go func(ping, pong chan int) { + var ball int + for { + select { + case ball = <-ping: + fmt.Println("Ping", ball) + time.Sleep(500 * time.Millisecond) + pong <- ball + 1 + case ball = <-pong: + fmt.Println("Pong", ball) + time.Sleep(500 * time.Millisecond) + ping <- ball + 1 + default: + fmt.Println("Time out!!!") + return + } + } + }(ping, pong) + + time.Sleep(2 * time.Second) + fmt.Println("Exit") +} diff --git a/part_9/9.5/13.go b/part_9/9.5/13.go new file mode 100644 index 0000000..2190271 --- /dev/null +++ b/part_9/9.5/13.go @@ -0,0 +1,40 @@ +package main + +import ( + "fmt" + "os" + "time" +) + +func main() { + ping := make(chan int, 1) + pong := make(chan int, 1) + + ping <- 1 + + go func(ping, pong chan int) { + timeChan := make(chan time.Time) + go func(timeChan chan time.Time) { + timeChan <- (<-time.After(time.Second * 2)) + }(timeChan) + + var ball int + for { + select { + case ball = <-ping: + fmt.Println("Ping", ball) + time.Sleep(500 * time.Millisecond) + pong <- ball + 1 + case ball = <-pong: + fmt.Println("Pong", ball) + time.Sleep(500 * time.Millisecond) + ping <- ball + 1 + case <-timeChan: + fmt.Println("Exit") + os.Exit(0) + } + } + }(ping, pong) + + select {} // вечное ожидание +} diff --git a/part_9/9.5/14.go b/part_9/9.5/14.go new file mode 100644 index 0000000..1a0a2c9 --- /dev/null +++ b/part_9/9.5/14.go @@ -0,0 +1,38 @@ +package main + +import ( + "fmt" + "time" +) + +func main() { + ping := make(chan int, 1) + pong := make(chan int, 1) + + ping <- 1 + + go func(ping, pong chan int) { + var ball int + for { + select { + case ball = <-ping: + fmt.Println("Ping", ball) + time.Sleep(500 * time.Millisecond) + if ball > 2 { + ping = nil + } else { + pong <- ball + 1 + } + case ball = <-pong: + fmt.Println("Pong", ball) + time.Sleep(500 * time.Millisecond) + ping <- ball + 1 + case value := <-time.After(time.Second): + fmt.Println("Time out!!!", value) + } + } + }(ping, pong) + + time.Sleep(4 * time.Second) + fmt.Println("Exit") +} diff --git a/part_9/9.5/15.go b/part_9/9.5/15.go new file mode 100644 index 0000000..b05a28c --- /dev/null +++ b/part_9/9.5/15.go @@ -0,0 +1,39 @@ +package main + +import ( + "fmt" +) + +type Rectangle struct { + Width uint + Length uint +} + +func (r *Rectangle) GetPerimeter() uint { + return (r.Length + r.Width) * 2 +} + +func (r *Rectangle) GetArea() uint { + return r.Length * r.Width +} + +func calculate(in <-chan Rectangle, out chan<- float64) { + var sum float64 + for i := range in { + sum += float64(i.GetPerimeter()) + } + out <- sum / float64(cap(in)) +} + +func main() { + inChan := make(chan Rectangle, 3) + outChan := make(chan float64) + go calculate(inChan, outChan) + + inChan <- Rectangle{14, 6} + inChan <- Rectangle{5, 21} + close(inChan) // закрытие канала + + result := <-outChan + fmt.Printf("Result = %v", result) +} diff --git a/part_9/9.5/2.go b/part_9/9.5/2.go new file mode 100644 index 0000000..098c28a --- /dev/null +++ b/part_9/9.5/2.go @@ -0,0 +1,23 @@ +package main + +import ( + "fmt" +) + +func myPrint(c chan int) { + for i := 0; i < 3; i++ { + value := <-c + fmt.Printf("%d ", value) + } + +} + +func main() { + myChannel := make(chan int, 3) // объявление буферизированного канала + defer close(myChannel) // отложенное закрытие канала + go myPrint(myChannel) + myChannel <- 3 + myChannel <- 10 // запись значения 10 в канал + myChannel <- 77 + fmt.Printf("\nExit") +} diff --git a/part_9/9.5/3.go b/part_9/9.5/3.go new file mode 100644 index 0000000..9b24f90 --- /dev/null +++ b/part_9/9.5/3.go @@ -0,0 +1,25 @@ +package main + +import ( + "fmt" +) + +func myPrint(c chan int) { + for i := 0; i < 3; i++ { + value := <-c + fmt.Printf("%d ", value) + } + +} + +func main() { + myChannel := make(chan int, 3) // объявление буферизированного канала + defer close(myChannel) // отложенное закрытие канала + go myPrint(myChannel) + myChannel <- 3 + myChannel <- 10 // запись значения 10 в канал + myChannel <- 77 + myChannel <- 105 + myChannel <- 104 + fmt.Printf("\nExit") +} diff --git a/part_9/9.5/4.go b/part_9/9.5/4.go new file mode 100644 index 0000000..9045063 --- /dev/null +++ b/part_9/9.5/4.go @@ -0,0 +1,23 @@ +package main + +import ( + "fmt" +) + +func myPrint(c chan int) { + for i := 0; i < 3; i++ { + value := <-c + fmt.Printf("%d ", value) + } + +} + +func main() { + myChannel := make(chan int, 3) // объявление буферизированного канала + defer close(myChannel) // отложенное закрытие канала + go myPrint(myChannel) + for i := 0; i < 10; i++ { + myChannel <- i + } + fmt.Printf("\nExit") +} diff --git a/part_9/9.5/5.go b/part_9/9.5/5.go new file mode 100644 index 0000000..af0f6f4 --- /dev/null +++ b/part_9/9.5/5.go @@ -0,0 +1,27 @@ +package main + +import ( + "fmt" + "time" +) + +func onlyRead(c <-chan int) { //только для чтения + for i := 0; i <= 3; i++ { + value := <-c + fmt.Printf("%d ", value) + } +} + +func onlyWrite(c chan<- int) { //только для записи + for i := 0; i <= 3; i++ { + c <- i + } +} + +func main() { + myChannel := make(chan int, 3) // объявление буферизированного канала + defer close(myChannel) // отложенное закрытие канала + go onlyRead(myChannel) + go onlyWrite(myChannel) + time.Sleep(time.Second) +} diff --git a/part_9/9.5/6.go b/part_9/9.5/6.go new file mode 100644 index 0000000..0f0e099 --- /dev/null +++ b/part_9/9.5/6.go @@ -0,0 +1,28 @@ +package main + +import ( + "fmt" + "time" +) + +func onlyRead(c <-chan int) { //только для чтения + c <- 4 + for i := 0; i <= 3; i++ { + value := <-c + fmt.Printf("%d ", value) + } +} + +func onlyWrite(c chan<- int) { //только для записи + for i := 0; i <= 3; i++ { + c <- i + } +} + +func main() { + myChannel := make(chan int, 3) // объявление буферизированного канала + defer close(myChannel) // отложенное закрытие канала + go onlyRead(myChannel) + go onlyWrite(myChannel) + time.Sleep(time.Second) +} diff --git a/part_9/9.5/7.go b/part_9/9.5/7.go new file mode 100644 index 0000000..c5d1f8c --- /dev/null +++ b/part_9/9.5/7.go @@ -0,0 +1,23 @@ +package main + +import ( + "fmt" +) + +func infoChan(c chan int) { + length, capacity := len(c), cap(c) + fmt.Printf("Length = %d, capacity = %d\n", length, capacity) +} + +func main() { + var value int + myChannel := make(chan int, 3) // объявление буферизированного канала + defer close(myChannel) // отложенное закрытие канала + infoChan(myChannel) + myChannel <- 1 + myChannel <- 2 + infoChan(myChannel) + value = <-myChannel + infoChan(myChannel) + fmt.Println(value) +} diff --git a/part_9/9.5/8.go b/part_9/9.5/8.go new file mode 100644 index 0000000..8ae9887 --- /dev/null +++ b/part_9/9.5/8.go @@ -0,0 +1,41 @@ +package main + +import ( + "fmt" +) + +type Rectangle struct { + Width uint + Length uint +} + +func (r *Rectangle) GetPerimeter() uint { + return (r.Length + r.Width) * 2 +} + +func (r *Rectangle) GetArea() uint { + return r.Length * r.Width +} + +func calculate(in <-chan Rectangle, out chan<- float64) { + var sum float64 + for i := 0; i <= 3; i++ { + reactangle := <-in + sum += float64(reactangle.GetPerimeter()) + } + out <- sum / float64(cap(in)) +} + +func main() { + inChan := make(chan Rectangle, 3) + outChan := make(chan float64) + go calculate(inChan, outChan) + + inChan <- Rectangle{14, 6} + inChan <- Rectangle{5, 21} + inChan <- Rectangle{10, 33} + inChan <- Rectangle{2, 5} + + result := <-outChan + fmt.Printf("Result = %v", result) +} diff --git a/part_9/9.5/9.go b/part_9/9.5/9.go new file mode 100644 index 0000000..a810bbd --- /dev/null +++ b/part_9/9.5/9.go @@ -0,0 +1,41 @@ +package main + +import ( + "fmt" + "time" +) + +func main() { + pingChan := make(chan int, 1) + pongChan := make(chan int, 1) + + go ping(pingChan, pongChan) + go pong(pongChan, pingChan) + + pingChan <- 1 + + time.Sleep(2 * time.Second) + fmt.Println("Exit") +} + +func ping(pingChan <-chan int, pongChan chan<- int) { + for { + ball := <-pingChan + + fmt.Println("Ping", ball) + time.Sleep(500 * time.Millisecond) + + pongChan <- ball + 1 + } +} + +func pong(pongChan <-chan int, pingChan chan<- int) { + for { + ball := <-pongChan + + fmt.Println("Pong", ball) + time.Sleep(500 * time.Millisecond) + + pingChan <- ball + 1 + } +} diff --git a/part_9/9.6/1.go b/part_9/9.6/1.go new file mode 100644 index 0000000..f9bfb0e --- /dev/null +++ b/part_9/9.6/1.go @@ -0,0 +1,23 @@ +package main + +import ( + "fmt" + "sync" +) + +var value = 0 + +func increment(waitGroup *sync.WaitGroup) { + value = value + 1 + waitGroup.Done() +} + +func main() { + var waitGroup sync.WaitGroup + for i := 0; i < 1000; i++ { + waitGroup.Add(1) + go increment(&waitGroup) + } + waitGroup.Wait() + fmt.Println("Value after 1k increment = ", value) +} diff --git a/part_9/9.7/1.go b/part_9/9.7/1.go new file mode 100644 index 0000000..d158be8 --- /dev/null +++ b/part_9/9.7/1.go @@ -0,0 +1,26 @@ +package main + +import ( + "fmt" + "sync" +) + +var value int + +func increment(waitGroup *sync.WaitGroup, mutex *sync.Mutex) { + mutex.Lock() // блокируем критический раздел + defer mutex.Unlock() // отложенная разблокировка + value = value + 1 + waitGroup.Done() +} + +func main() { + var waitGroup sync.WaitGroup + mutex := new(sync.Mutex) // либо var mutex sync.Mutex + for i := 0; i < 1000; i++ { + waitGroup.Add(1) + go increment(&waitGroup, mutex) + } + waitGroup.Wait() + fmt.Println("Value after 1k increment = ", value) +} diff --git a/part_9/9.7/2.go b/part_9/9.7/2.go new file mode 100644 index 0000000..08bed1e --- /dev/null +++ b/part_9/9.7/2.go @@ -0,0 +1,26 @@ +package main + +import ( + "fmt" + "sync" +) + +var value int + +func increment(waitGroup *sync.WaitGroup, c chan bool) { + c <- true // блокируем критический раздел + value = value + 1 + <-c // разблокировка критического раздела + waitGroup.Done() +} + +func main() { + var waitGroup sync.WaitGroup + myChan := make(chan bool, 1) + for i := 0; i < 1000; i++ { + waitGroup.Add(1) + go increment(&waitGroup, myChan) + } + waitGroup.Wait() + fmt.Println("Value after 1k increment = ", value) +} diff --git a/part_9/9.7/3.go b/part_9/9.7/3.go new file mode 100644 index 0000000..8934ab4 --- /dev/null +++ b/part_9/9.7/3.go @@ -0,0 +1,94 @@ +package main + +import ( + "fmt" + "sync" + "time" +) + +const count = 100 + +type Person struct { + ID uint64 + Name string + Age uint8 +} + +type Account struct { + id uint64 + owner Person + balance int + lock sync.RWMutex +} + +func (a *Account) WithdrawMoney(amount int) { + a.lock.Lock() + defer a.lock.Unlock() + a.balance -= amount +} + +func (a *Account) DepositMoney(amount int) { + a.lock.Lock() + defer a.lock.Unlock() + a.balance += amount +} + +func (a *Account) GetBalance() int { + a.lock.RLock() + defer a.lock.RUnlock() + return a.balance +} + +func NewAccount(id uint64, owner Person, balance int) *Account { + return &Account{ + id: 123213123123, + owner: owner, + balance: balance, + } +} + +func WithdrawMoney(waitGroup *sync.WaitGroup, account *Account) { + for i := 0; i < count; i++ { + account.WithdrawMoney(i) + time.Sleep(time.Microsecond) + } + waitGroup.Done() +} + +func DepositMoney(waitGroup *sync.WaitGroup, account *Account) { + for i := 0; i < count; i++ { + account.DepositMoney(i) + time.Sleep(time.Microsecond) + } + waitGroup.Done() +} + +func PrintBalance(number int, account *Account) { + for { + fmt.Printf("%d)Current account balance = %d\n", + number, account.GetBalance()) + time.Sleep(150 * time.Millisecond) + } +} + +func main() { + var waitGroup sync.WaitGroup + account := NewAccount( + 324234234, + Person{ + ID: 233424, + Name: "Alex", + Age: 21, + }, + 30000, + ) + waitGroup.Add(2) + go WithdrawMoney(&waitGroup, account) + go DepositMoney(&waitGroup, account) + for i := 0; i <= 3; i++ { + go PrintBalance(i, account) + time.Sleep(50 * time.Millisecond) + } + waitGroup.Wait() + fmt.Printf("Final account balance = %d", account.GetBalance()) +} diff --git a/part_9/9.8/1.go b/part_9/9.8/1.go new file mode 100644 index 0000000..2c66dfd --- /dev/null +++ b/part_9/9.8/1.go @@ -0,0 +1,24 @@ +package main + +import ( + "fmt" + "sync" + "sync/atomic" +) + +var value int64 = 0 + +func increment(waitGroup *sync.WaitGroup) { + atomic.AddInt64(&value, 1) + waitGroup.Done() +} + +func main() { + var waitGroup sync.WaitGroup + for i := 0; i < 1000; i++ { + waitGroup.Add(1) + go increment(&waitGroup) + } + waitGroup.Wait() + fmt.Println("Value after 1k increment = ", value) +} diff --git a/part_9/9.8/2.go b/part_9/9.8/2.go new file mode 100644 index 0000000..340af8f --- /dev/null +++ b/part_9/9.8/2.go @@ -0,0 +1,39 @@ +package main + +import ( + "fmt" + "sync" + "sync/atomic" +) + +type AtomicCounter struct { + value int64 +} + +func (a *AtomicCounter) Increment() { + atomic.AddInt64(&a.value, 1) +} + +func (a *AtomicCounter) Decrement() { + atomic.AddInt64(&a.value, -1) +} + +func (a *AtomicCounter) Value() int64 { + return atomic.LoadInt64(&a.value) +} + +func increment(waitGroup *sync.WaitGroup, counter *AtomicCounter) { + counter.Increment() + waitGroup.Done() +} + +func main() { + var waitGroup sync.WaitGroup + counter := &AtomicCounter{0} + for i := 0; i < 1000; i++ { + waitGroup.Add(1) + go increment(&waitGroup, counter) + } + waitGroup.Wait() + fmt.Println("Value after 1k increment = ", counter.Value()) +} diff --git a/part_9/9.9/1.go b/part_9/9.9/1.go new file mode 100644 index 0000000..ee32f4d --- /dev/null +++ b/part_9/9.9/1.go @@ -0,0 +1,15 @@ +package main + +import ( + "fmt" + "runtime" +) + +func getGOMAXPROCS() int { + return runtime.GOMAXPROCS(0) +} + +func main() { + fmt.Printf("GOMAXPROCS: %d\n", runtime.NumCPU()) + // NumCPU возвращает количество логических CPU, используемых текущим процессом. +} diff --git a/part_9/9.9/2.go b/part_9/9.9/2.go new file mode 100644 index 0000000..cd37566 --- /dev/null +++ b/part_9/9.9/2.go @@ -0,0 +1,47 @@ +package main + +import ( + "fmt" + "runtime" + "sync" + "sync/atomic" + "time" +) + +type AtomicCounter struct { + value int64 +} + +func (a *AtomicCounter) Increment() { + atomic.AddInt64(&a.value, 1) +} + +func (a *AtomicCounter) Decrement() { + atomic.AddInt64(&a.value, -1) +} + +func (a *AtomicCounter) Value() int64 { + return atomic.LoadInt64(&a.value) +} + +func increment(waitGroup *sync.WaitGroup, counter *AtomicCounter) { + counter.Increment() + waitGroup.Done() +} + +func getGOMAXPROCS() int { + return runtime.GOMAXPROCS(0) +} + +func main() { + var waitGroup sync.WaitGroup + counter := &AtomicCounter{0} + myTime := time.Now() + for i := 0; i < 100_000; i++ { + waitGroup.Add(1) + go increment(&waitGroup, counter) + } + waitGroup.Wait() + fmt.Println("Value after 1k increment = ", counter.Value()) + fmt.Printf("Time work: %v", time.Since(myTime)) +}