mirror of
https://github.com/MADTeacher/go_basics.git
synced 2025-11-23 21:34:47 +02:00
Переработана 5-я глава
This commit is contained in:
16
part_5/5.1/1.go
Normal file
16
part_5/5.1/1.go
Normal file
@@ -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() // закрытие файла
|
||||
}
|
||||
15
part_5/5.1/10.go
Normal file
15
part_5/5.1/10.go
Normal file
@@ -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))
|
||||
}
|
||||
25
part_5/5.1/11.go
Normal file
25
part_5/5.1/11.go
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
26
part_5/5.1/12.go
Normal file
26
part_5/5.1/12.go
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
19
part_5/5.1/13.go
Normal file
19
part_5/5.1/13.go
Normal file
@@ -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)
|
||||
}
|
||||
19
part_5/5.1/14.go
Normal file
19
part_5/5.1/14.go
Normal file
@@ -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)
|
||||
}
|
||||
22
part_5/5.1/15.go
Normal file
22
part_5/5.1/15.go
Normal file
@@ -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))
|
||||
}
|
||||
34
part_5/5.1/16.go
Normal file
34
part_5/5.1/16.go
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
45
part_5/5.1/17.go
Normal file
45
part_5/5.1/17.go
Normal file
@@ -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, "байт")
|
||||
}
|
||||
}
|
||||
46
part_5/5.1/18.go
Normal file
46
part_5/5.1/18.go
Normal file
@@ -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, "байт")
|
||||
}
|
||||
}
|
||||
39
part_5/5.1/19.go
Normal file
39
part_5/5.1/19.go
Normal file
@@ -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)
|
||||
}
|
||||
19
part_5/5.1/2.go
Normal file
19
part_5/5.1/2.go
Normal file
@@ -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())
|
||||
}
|
||||
40
part_5/5.1/20.go
Normal file
40
part_5/5.1/20.go
Normal file
@@ -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)
|
||||
}
|
||||
17
part_5/5.1/3.go
Normal file
17
part_5/5.1/3.go
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
14
part_5/5.1/4.go
Normal file
14
part_5/5.1/4.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
pathToFile := "test.txt"
|
||||
err := os.Remove(pathToFile)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
20
part_5/5.1/5.go
Normal file
20
part_5/5.1/5.go
Normal file
@@ -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)
|
||||
}
|
||||
23
part_5/5.1/6.go
Normal file
23
part_5/5.1/6.go
Normal file
@@ -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")
|
||||
}
|
||||
29
part_5/5.1/7.go
Normal file
29
part_5/5.1/7.go
Normal file
@@ -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")
|
||||
}
|
||||
28
part_5/5.1/8.go
Normal file
28
part_5/5.1/8.go
Normal file
@@ -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))
|
||||
}
|
||||
22
part_5/5.1/9.go
Normal file
22
part_5/5.1/9.go
Normal file
@@ -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))
|
||||
}
|
||||
15
part_5/5.2/1.go
Normal file
15
part_5/5.2/1.go
Normal file
@@ -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")
|
||||
}
|
||||
26
part_5/5.2/10.go
Normal file
26
part_5/5.2/10.go
Normal file
@@ -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)
|
||||
}
|
||||
22
part_5/5.2/11.go
Normal file
22
part_5/5.2/11.go
Normal file
@@ -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") // перемещение
|
||||
}
|
||||
18
part_5/5.2/12.go
Normal file
18
part_5/5.2/12.go
Normal file
@@ -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")
|
||||
}
|
||||
}
|
||||
15
part_5/5.2/2.go
Normal file
15
part_5/5.2/2.go
Normal file
@@ -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")
|
||||
}
|
||||
48
part_5/5.2/3.go
Normal file
48
part_5/5.2/3.go
Normal file
@@ -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)
|
||||
}
|
||||
62
part_5/5.2/4.go
Normal file
62
part_5/5.2/4.go
Normal file
@@ -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) // удаление всех временных каталогов
|
||||
}
|
||||
26
part_5/5.2/5.go
Normal file
26
part_5/5.2/5.go
Normal file
@@ -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)
|
||||
}
|
||||
26
part_5/5.2/6.go
Normal file
26
part_5/5.2/6.go
Normal file
@@ -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()))
|
||||
}
|
||||
}
|
||||
}
|
||||
16
part_5/5.2/7.go
Normal file
16
part_5/5.2/7.go
Normal file
@@ -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
|
||||
}
|
||||
27
part_5/5.2/8.go
Normal file
27
part_5/5.2/8.go
Normal file
@@ -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()
|
||||
}
|
||||
21
part_5/5.2/9.go
Normal file
21
part_5/5.2/9.go
Normal file
@@ -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()
|
||||
}
|
||||
30
part_5/5.3/1.go
Normal file
30
part_5/5.3/1.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
type Actor struct {
|
||||
Name string
|
||||
Age int
|
||||
FilmsAmount int
|
||||
AboutActor string
|
||||
}
|
||||
|
||||
func main() {
|
||||
actor := Actor{
|
||||
Name: "Tom Hanks",
|
||||
Age: 65,
|
||||
FilmsAmount: 50,
|
||||
AboutActor: "Tom Hanks is an actor...",
|
||||
}
|
||||
|
||||
actorJson, err := json.Marshal(actor)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(string(actorJson))
|
||||
}
|
||||
36
part_5/5.3/2.go
Normal file
36
part_5/5.3/2.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Actor struct {
|
||||
Name string
|
||||
Age int
|
||||
FilmsAmount int
|
||||
AboutActor string
|
||||
}
|
||||
|
||||
func main() {
|
||||
actor := Actor{
|
||||
Name: "Tom Hanks",
|
||||
Age: 65,
|
||||
FilmsAmount: 50,
|
||||
AboutActor: "Tom Hanks is an actor...",
|
||||
}
|
||||
|
||||
actorJson, err := json.MarshalIndent(actor, "", " ")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
myFile, err := os.Create("actor.json")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
myFile.Write(actorJson)
|
||||
defer myFile.Close()
|
||||
}
|
||||
31
part_5/5.3/3.go
Normal file
31
part_5/5.3/3.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Actor struct {
|
||||
Name string
|
||||
Age int
|
||||
FilmsAmount int
|
||||
AboutActor string
|
||||
}
|
||||
|
||||
func main() {
|
||||
actor := &Actor{}
|
||||
|
||||
data, err := os.ReadFile("actor.json")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(data, actor)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Printf("%+v", *actor)
|
||||
}
|
||||
43
part_5/5.3/4.go
Normal file
43
part_5/5.3/4.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Actor struct {
|
||||
Name string
|
||||
Age int
|
||||
FilmsAmount int
|
||||
AboutActor *string
|
||||
}
|
||||
|
||||
func main() {
|
||||
actor := &Actor{}
|
||||
|
||||
data, err := os.ReadFile("actor.json")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(data, actor)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Выводим данные, прочитанные из файла
|
||||
fmt.Print("Deserialized data: ")
|
||||
fmt.Printf("%+v\n", *actor)
|
||||
|
||||
actorJson, err := json.MarshalIndent(actor, "", " ") // сериализация
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Выводим сериализованные данные
|
||||
fmt.Println()
|
||||
fmt.Println("Serialized data:")
|
||||
fmt.Println(string(actorJson))
|
||||
}
|
||||
33
part_5/5.3/5.go
Normal file
33
part_5/5.3/5.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
type Actor struct {
|
||||
// имя поля при сериализации/десериализации
|
||||
Name string `json:"name"`
|
||||
Age int `json:"age"`
|
||||
// имя тега может отличаться от имени поля структуры
|
||||
FilmsAmount int `json:"films_amount"`
|
||||
AboutActor *string `json:"about"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
aboutStr := "Tom Hanks is an actor..."
|
||||
actor := Actor{
|
||||
Name: "Tom Hanks",
|
||||
Age: 65,
|
||||
FilmsAmount: 50,
|
||||
AboutActor: &aboutStr,
|
||||
}
|
||||
|
||||
actorJson, err := json.MarshalIndent(actor, "", " ")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(string(actorJson))
|
||||
}
|
||||
33
part_5/5.3/6.go
Normal file
33
part_5/5.3/6.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
type Actor struct {
|
||||
// имя поля при сериализации/десериализации
|
||||
Name string `json:"name"`
|
||||
Age int `json:"-"`
|
||||
// имя тега может отличаться от имени поля структуры
|
||||
FilmsAmount int `json:"-"`
|
||||
AboutActor *string `json:"about"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
aboutStr := "Tom Hanks is an actor..."
|
||||
actor := Actor{
|
||||
Name: "Tom Hanks",
|
||||
Age: 65,
|
||||
FilmsAmount: 50,
|
||||
AboutActor: &aboutStr,
|
||||
}
|
||||
|
||||
actorJson, err := json.MarshalIndent(actor, "", " ")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(string(actorJson))
|
||||
}
|
||||
54
part_5/5.3/7.go
Normal file
54
part_5/5.3/7.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
type Actor struct {
|
||||
// имя поля при сериализации/десериализации
|
||||
Name string `json:"name"`
|
||||
Age int `json:"age"`
|
||||
// имя тега может отличаться от имени поля структуры
|
||||
FilmsAmount int `json:"films_amount,omitempty"`
|
||||
AboutActor *string `json:",omitempty"`
|
||||
}
|
||||
|
||||
func ActorToBytes(actor Actor) []byte {
|
||||
actorJson, err := json.MarshalIndent(actor, "", " ")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return actorJson
|
||||
}
|
||||
|
||||
func main() {
|
||||
aboutStr := "Tom Hanks is an actor..."
|
||||
// поле FilmsAmount проинициализируется значением
|
||||
// по умолчанию
|
||||
actor := Actor{
|
||||
Name: "Tom Hanks",
|
||||
Age: 65,
|
||||
AboutActor: &aboutStr,
|
||||
}
|
||||
|
||||
actorJson := ActorToBytes(actor)
|
||||
// Выводим сериализованные данные
|
||||
fmt.Println()
|
||||
fmt.Println("First serialized data:")
|
||||
fmt.Println(string(actorJson))
|
||||
|
||||
// поле AboutActor и Age проинициализируются значением
|
||||
// по умолчанию
|
||||
actor = Actor{
|
||||
Name: "Tom Hanks",
|
||||
FilmsAmount: 150,
|
||||
}
|
||||
|
||||
actorJson = ActorToBytes(actor)
|
||||
// Выводим сериализованные данные
|
||||
fmt.Println()
|
||||
fmt.Println("Second serialized data:")
|
||||
fmt.Println(string(actorJson))
|
||||
}
|
||||
32
part_5/5.3/8.go
Normal file
32
part_5/5.3/8.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Actor struct {
|
||||
// имя поля при сериализации/десериализации
|
||||
Name string `json:"name"`
|
||||
Age int `json:"age"`
|
||||
// имя тега может отличаться от имени поля структуры
|
||||
FilmsAmount int `json:"films_amount,omitempty"`
|
||||
AboutActor *string `json:",omitempty"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
actorJson := map[string]any{}
|
||||
|
||||
data, err := os.ReadFile("actor.json")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(data, &actorJson)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Printf("%+v", actorJson)
|
||||
}
|
||||
3
part_5/5.3/filmography/go.mod
Normal file
3
part_5/5.3/filmography/go.mod
Normal file
@@ -0,0 +1,3 @@
|
||||
module filmography
|
||||
|
||||
go 1.24.3
|
||||
8
part_5/5.3/filmography/imdb/actor.go
Normal file
8
part_5/5.3/filmography/imdb/actor.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package imdb
|
||||
|
||||
type Actor struct {
|
||||
Name string `json:"name"`
|
||||
Age int `json:"age"`
|
||||
FilmsAmount int `json:"filmsAmount"`
|
||||
AboutActor string `json:"aboutActor"`
|
||||
}
|
||||
5
part_5/5.3/filmography/imdb/genre.go
Normal file
5
part_5/5.3/filmography/imdb/genre.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package imdb
|
||||
|
||||
type Genre struct {
|
||||
Types []string `json:"types"`
|
||||
}
|
||||
13
part_5/5.3/filmography/imdb/movie.go
Normal file
13
part_5/5.3/filmography/imdb/movie.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package imdb
|
||||
|
||||
type Movie struct {
|
||||
Name string `json:"name"`
|
||||
Budget int `json:"budget"`
|
||||
Actors []Actor `json:"actors"`
|
||||
CriticsRating float64 `json:"criticsRating"`
|
||||
AudienceRating float64 `json:"audienceRating"`
|
||||
Year int `json:"year"`
|
||||
Country string `json:"country"`
|
||||
Genre Genre `json:"genre"`
|
||||
Reviews []Review `json:"reviews"`
|
||||
}
|
||||
7
part_5/5.3/filmography/imdb/review.go
Normal file
7
part_5/5.3/filmography/imdb/review.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package imdb
|
||||
|
||||
type Review struct {
|
||||
Name string `json:"name"`
|
||||
Text string `json:"text"`
|
||||
Rating int `json:"rating"`
|
||||
}
|
||||
33
part_5/5.3/filmography/main.go
Normal file
33
part_5/5.3/filmography/main.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"filmography/imdb"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
movie := &imdb.Movie{}
|
||||
data, err := os.ReadFile("movie.json")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(data, &movie)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Printf("%+v", movie)
|
||||
|
||||
// записать в файл output.json
|
||||
data, err = json.MarshalIndent(movie, "", " ")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = os.WriteFile("output.json", data, 0644)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
52
part_5/5.3/filmography/movie.json
Normal file
52
part_5/5.3/filmography/movie.json
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"name": "Prevozmogun",
|
||||
"budget": 2000000,
|
||||
"actors": [
|
||||
{
|
||||
"name": "Alexey",
|
||||
"age": 25,
|
||||
"filmsAmount": 3,
|
||||
"aboutActor": "2 academy awards"
|
||||
},
|
||||
{
|
||||
"name": "Max",
|
||||
"age": 33,
|
||||
"filmsAmount": 2,
|
||||
"aboutActor": "Very good actor"
|
||||
},
|
||||
{
|
||||
"name": "Natalya",
|
||||
"age": 18,
|
||||
"filmsAmount": 1,
|
||||
"aboutActor": "Rising star"
|
||||
}
|
||||
],
|
||||
"criticsRating": 7.5,
|
||||
"audienceRating": 8.5,
|
||||
"year": 2019,
|
||||
"country": "Russia",
|
||||
"genre": {
|
||||
"types": [
|
||||
"Comedy",
|
||||
"Drama",
|
||||
"Romance"
|
||||
]
|
||||
},
|
||||
"reviews": [
|
||||
{
|
||||
"name": "Igor",
|
||||
"text": "I love this movie",
|
||||
"rating": 10
|
||||
},
|
||||
{
|
||||
"name": "John",
|
||||
"text": "I hate this movie",
|
||||
"rating": 1
|
||||
},
|
||||
{
|
||||
"name": "Stas",
|
||||
"text": "I like this movie",
|
||||
"rating": 7
|
||||
}
|
||||
]
|
||||
}
|
||||
52
part_5/5.3/filmography/output.json
Normal file
52
part_5/5.3/filmography/output.json
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"name": "Prevozmogun",
|
||||
"budget": 2000000,
|
||||
"actors": [
|
||||
{
|
||||
"name": "Alexey",
|
||||
"age": 25,
|
||||
"filmsAmount": 3,
|
||||
"aboutActor": "2 academy awards"
|
||||
},
|
||||
{
|
||||
"name": "Max",
|
||||
"age": 33,
|
||||
"filmsAmount": 2,
|
||||
"aboutActor": "Very good actor"
|
||||
},
|
||||
{
|
||||
"name": "Natalya",
|
||||
"age": 18,
|
||||
"filmsAmount": 1,
|
||||
"aboutActor": "Rising star"
|
||||
}
|
||||
],
|
||||
"criticsRating": 7.5,
|
||||
"audienceRating": 8.5,
|
||||
"year": 2019,
|
||||
"country": "Russia",
|
||||
"genre": {
|
||||
"types": [
|
||||
"Comedy",
|
||||
"Drama",
|
||||
"Romance"
|
||||
]
|
||||
},
|
||||
"reviews": [
|
||||
{
|
||||
"name": "Igor",
|
||||
"text": "I love this movie",
|
||||
"rating": 10
|
||||
},
|
||||
{
|
||||
"name": "John",
|
||||
"text": "I hate this movie",
|
||||
"rating": 1
|
||||
},
|
||||
{
|
||||
"name": "Stas",
|
||||
"text": "I like this movie",
|
||||
"rating": 7
|
||||
}
|
||||
]
|
||||
}
|
||||
162
part_5/5.6/go_dotenv/dotenv/dotenv.go
Normal file
162
part_5/5.6/go_dotenv/dotenv/dotenv.go
Normal file
@@ -0,0 +1,162 @@
|
||||
package dotenv
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"maps"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type DotEnv struct {
|
||||
env map[string]interface{}
|
||||
}
|
||||
|
||||
// Регулярные выражения для int и bool
|
||||
var (
|
||||
intPattern = regexp.MustCompile(`^-?\d+$`)
|
||||
boolPattern = regexp.MustCompile(`^(?i:true|false)$`)
|
||||
)
|
||||
|
||||
// Создаем новый экземпляр DotEnv
|
||||
// platformEnv указывает, загружать ли переменные из окружения ОС
|
||||
func NewDotEnv(platformEnv bool) *DotEnv {
|
||||
d := &DotEnv{env: make(map[string]interface{})}
|
||||
if platformEnv {
|
||||
d.env = mergeMaps(d.env, loadPlatformEnv())
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// Загружаем переменные из .env файлов
|
||||
func (d *DotEnv) Load(paths ...string) error {
|
||||
if len(paths) == 0 {
|
||||
paths = []string{".env"}
|
||||
}
|
||||
for _, path := range paths {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf(".env file not found: %s", path)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
localEnv, err := loadLocalEnv(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.env = mergeMaps(d.env, localEnv)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Возвращает значение переменной окружения по ключу
|
||||
func (d *DotEnv) GetValue(key string) (interface{}, error) {
|
||||
val, ok := d.env[key]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("key not found: %s", key)
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
|
||||
// Возвращает значение переменной окружения по ключу,
|
||||
// приведенное к int. Если значение не является int,
|
||||
// возвращается ошибка.
|
||||
func (d *DotEnv) GetInt(key string) (int, error) {
|
||||
val, ok := d.env[key]
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("key not found: %s", key)
|
||||
}
|
||||
i, ok := val.(int)
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("value for key %s is not an int", key)
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
// Возвращает значение переменной окружения по ключу,
|
||||
// приведенное к bool. Если значение не является bool,
|
||||
// возвращается ошибка.
|
||||
func (d *DotEnv) GetBool(key string) (bool, error) {
|
||||
val, ok := d.env[key]
|
||||
if !ok {
|
||||
return false, fmt.Errorf("key not found: %s", key)
|
||||
}
|
||||
b, ok := val.(bool)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("value for key %s is not a bool", key)
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Возвращает значение переменной окружения по ключу,
|
||||
// приведенное к string.
|
||||
func (d *DotEnv) GetString(key string) (string, error) {
|
||||
val, ok := d.env[key]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("key not found: %s", key)
|
||||
}
|
||||
s, ok := val.(string)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("value for key %s is not a string", key)
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// Преобразование таблицы из переменных окружения ОС
|
||||
func loadPlatformEnv() map[string]interface{} {
|
||||
config := make(map[string]interface{})
|
||||
for _, value := range os.Environ() {
|
||||
parts := strings.SplitN(value, "=", 2)
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
k := parts[0]
|
||||
v := parts[1]
|
||||
|
||||
config[k] = parseValue(v)
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
// Загрузка из локального .env файла
|
||||
func loadLocalEnv(file *os.File) (map[string]interface{}, error) {
|
||||
scanner := bufio.NewScanner(file)
|
||||
config := make(map[string]interface{})
|
||||
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
parts := strings.SplitN(line, "=", 2)
|
||||
if len(parts) != 2 {
|
||||
return nil, errors.New("invalid line in .env file: " + line)
|
||||
}
|
||||
key := strings.TrimSpace(parts[0])
|
||||
val := strings.TrimSpace(parts[1])
|
||||
config[key] = parseValue(val)
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// Парсинг строки в int, bool или string
|
||||
func parseValue(val string) interface{} {
|
||||
if intPattern.MatchString(val) {
|
||||
if i, err := strconv.Atoi(val); err == nil {
|
||||
return i
|
||||
}
|
||||
}
|
||||
if boolPattern.MatchString(val) {
|
||||
return strings.ToLower(val) == "true"
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// Объединение двух map
|
||||
func mergeMaps(a, b map[string]interface{}) map[string]interface{} {
|
||||
maps.Copy(a, b)
|
||||
return a
|
||||
}
|
||||
3
part_5/5.6/go_dotenv/go.mod
Normal file
3
part_5/5.6/go_dotenv/go.mod
Normal file
@@ -0,0 +1,3 @@
|
||||
module go_dotenv
|
||||
|
||||
go 1.24.0
|
||||
40
part_5/5.6/go_dotenv/main.go
Normal file
40
part_5/5.6/go_dotenv/main.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go_dotenv/dotenv"
|
||||
"log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
env := dotenv.NewDotEnv(false)
|
||||
|
||||
err := env.Load(".env")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
adminID, err := env.GetInt("ADMIN_ID")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println(adminID)
|
||||
|
||||
adminPassword, err := env.GetString("ADMIN_PASSWORD")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println(adminPassword)
|
||||
|
||||
adminMode, err := env.GetBool("ADMIN_MODE")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println(adminMode)
|
||||
|
||||
adminEmail, err := env.GetString("ADMIN_EMAIL")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println(adminEmail)
|
||||
}
|
||||
3
part_5/5.6/my_app/go.mod
Normal file
3
part_5/5.6/my_app/go.mod
Normal file
@@ -0,0 +1,3 @@
|
||||
module my_app
|
||||
|
||||
go 1.24.0
|
||||
24
part_5/5.6/my_app/main.go
Normal file
24
part_5/5.6/my_app/main.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// конфигурируем флаги:
|
||||
// Первый аргумент - название флага
|
||||
// Второй - значение по умолчанию
|
||||
// Третий - описание того, что делает флаг
|
||||
myStr := flag.String("str", "value", "StrFlag description")
|
||||
myInt := flag.Int("int", 0, "IntFlag description")
|
||||
myBool := flag.Bool("bool", false, "BoolFlag description")
|
||||
|
||||
// Запускаем парсинг флагов, подаваемых в командной строке
|
||||
flag.Parse()
|
||||
|
||||
// используем флаги
|
||||
fmt.Println("String flag:", *myStr)
|
||||
fmt.Println("Int flag:", *myInt)
|
||||
fmt.Println("Bool flag:", *myBool)
|
||||
}
|
||||
3
part_5/5.6/my_compile_app/go.mod
Normal file
3
part_5/5.6/my_compile_app/go.mod
Normal file
@@ -0,0 +1,3 @@
|
||||
module my_compile_app
|
||||
|
||||
go 1.24.0
|
||||
12
part_5/5.6/my_compile_app/main.go
Normal file
12
part_5/5.6/my_compile_app/main.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var VersionType = "dev"
|
||||
var Version = "0.0.1"
|
||||
|
||||
func main() {
|
||||
fmt.Printf("Version: %s (%s)\n", Version, VersionType)
|
||||
}
|
||||
6
part_5/5.6/my_embed_app/embed_config.json
Normal file
6
part_5/5.6/my_embed_app/embed_config.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"debug": true,
|
||||
"offset": 10,
|
||||
"version": "0.0.1",
|
||||
"app_name": "StaskoGo"
|
||||
}
|
||||
3
part_5/5.6/my_embed_app/go.mod
Normal file
3
part_5/5.6/my_embed_app/go.mod
Normal file
@@ -0,0 +1,3 @@
|
||||
module my_embed_app
|
||||
|
||||
go 1.24.0
|
||||
32
part_5/5.6/my_embed_app/main.go
Normal file
32
part_5/5.6/my_embed_app/main.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
//go:embed embed_config.json
|
||||
var configData []byte
|
||||
|
||||
type Config struct {
|
||||
Debug bool `json:"debug"`
|
||||
Offset int `json:"offset"`
|
||||
AppName string `json:"app_name"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
func getConfig() Config {
|
||||
var config Config
|
||||
err := json.Unmarshal(configData, &config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
func main() {
|
||||
config := getConfig()
|
||||
fmt.Println(config)
|
||||
}
|
||||
14
part_5/go_database/.vscode/launch.json
vendored
Normal file
14
part_5/go_database/.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
{
|
||||
"name": "Launch Package",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "auto",
|
||||
"program": "${fileDirname}",
|
||||
"console": "integratedTerminal"
|
||||
}
|
||||
]
|
||||
}
|
||||
218
part_5/go_database/database/database.go
Normal file
218
part_5/go_database/database/database.go
Normal file
@@ -0,0 +1,218 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type DBType int
|
||||
|
||||
const (
|
||||
SUAI DBType = iota
|
||||
UNECON
|
||||
)
|
||||
|
||||
type Database struct {
|
||||
PathToSuaiDB string
|
||||
PathToUneconDB string
|
||||
SuaiUsers *Table[*User]
|
||||
UneconUsers *Table[*User]
|
||||
}
|
||||
|
||||
func NewDatabase(pathToSuaiDB, pathToUneconDB string) *Database {
|
||||
db := &Database{
|
||||
PathToSuaiDB: pathToSuaiDB,
|
||||
PathToUneconDB: pathToUneconDB,
|
||||
}
|
||||
|
||||
if _, err := os.Stat(pathToSuaiDB); os.IsNotExist(err) {
|
||||
dir := filepath.Dir(pathToSuaiDB)
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
fmt.Println("Error creating directory:", err)
|
||||
}
|
||||
|
||||
file, err := os.Create(pathToSuaiDB)
|
||||
if err != nil {
|
||||
fmt.Println("Error creating file:", err)
|
||||
}
|
||||
file.Close()
|
||||
db.SuaiUsers = NewTable[*User]("suai")
|
||||
} else {
|
||||
db.SuaiUsers = db.openTable(pathToSuaiDB, "suai")
|
||||
}
|
||||
|
||||
if _, err := os.Stat(pathToUneconDB); os.IsNotExist(err) {
|
||||
dir := filepath.Dir(pathToUneconDB)
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
fmt.Println("Error creating directory:", err)
|
||||
}
|
||||
|
||||
file, err := os.Create(pathToUneconDB)
|
||||
if err != nil {
|
||||
fmt.Println("Error creating file:", err)
|
||||
}
|
||||
file.Close()
|
||||
db.UneconUsers = NewTable[*User]("unecon")
|
||||
} else {
|
||||
db.UneconUsers = db.openTable(pathToUneconDB, "unecon")
|
||||
}
|
||||
|
||||
return db
|
||||
}
|
||||
|
||||
func (db *Database) openTable(filePath, tableName string) *Table[*User] {
|
||||
table := NewTable[*User](tableName)
|
||||
|
||||
file, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
fmt.Println("Error opening file:", err)
|
||||
return table
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
data := strings.Split(line, ",")
|
||||
if len(data) >= 7 {
|
||||
id, _ := strconv.Atoi(data[0])
|
||||
yearOfBirth, _ := strconv.Atoi(data[2])
|
||||
|
||||
user := NewUser(
|
||||
id,
|
||||
data[1],
|
||||
yearOfBirth,
|
||||
data[3],
|
||||
data[4],
|
||||
data[5],
|
||||
data[6],
|
||||
)
|
||||
|
||||
table.Insert(user)
|
||||
}
|
||||
}
|
||||
|
||||
return table
|
||||
}
|
||||
|
||||
func (db *Database) Save(dbType DBType) {
|
||||
var filePath string
|
||||
var users *Table[*User]
|
||||
|
||||
switch dbType {
|
||||
case SUAI:
|
||||
filePath = db.PathToSuaiDB
|
||||
users = db.SuaiUsers
|
||||
case UNECON:
|
||||
filePath = db.PathToUneconDB
|
||||
users = db.UneconUsers
|
||||
}
|
||||
|
||||
file, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
fmt.Println("Error opening file for writing:", err)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
writer := bufio.NewWriter(file)
|
||||
users.ForEach(func(user *User) {
|
||||
line := fmt.Sprintf("%d,%s,%d,%s,%s,%s,%s\n",
|
||||
user.ID(),
|
||||
user.Nickname(),
|
||||
user.YearOfBirth(),
|
||||
user.Email(),
|
||||
user.Phone(),
|
||||
user.AccessLevel(),
|
||||
user.PasswordHash(),
|
||||
)
|
||||
writer.WriteString(line)
|
||||
})
|
||||
writer.Flush()
|
||||
}
|
||||
|
||||
func (db *Database) Insert(user *User, dbType DBType) bool {
|
||||
var filePath string
|
||||
var isOk bool
|
||||
|
||||
switch dbType {
|
||||
case SUAI:
|
||||
filePath = db.PathToSuaiDB
|
||||
isOk = db.SuaiUsers.Insert(user)
|
||||
case UNECON:
|
||||
filePath = db.PathToUneconDB
|
||||
isOk = db.UneconUsers.Insert(user)
|
||||
}
|
||||
|
||||
if !isOk {
|
||||
return false
|
||||
}
|
||||
|
||||
file, err := os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
fmt.Println("Error opening file for appending:", err)
|
||||
return false
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
line := fmt.Sprintf("%d,%s,%d,%s,%s,%s,%s\n",
|
||||
user.ID(),
|
||||
user.Nickname(),
|
||||
user.YearOfBirth(),
|
||||
user.Email(),
|
||||
user.Phone(),
|
||||
user.AccessLevel(),
|
||||
user.PasswordHash(),
|
||||
)
|
||||
|
||||
if _, err := file.WriteString(line); err != nil {
|
||||
fmt.Println("Error writing to file:", err)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (db *Database) Selection(dbType DBType,
|
||||
attribute, value string) *Table[*User] {
|
||||
switch dbType {
|
||||
case SUAI:
|
||||
return db.SuaiUsers.Selection(attribute, value)
|
||||
case UNECON:
|
||||
return db.UneconUsers.Selection(attribute, value)
|
||||
default:
|
||||
return NewTable[*User]("empty")
|
||||
}
|
||||
}
|
||||
|
||||
func (db *Database) Intersect(attribute, value string) *Table[*User] {
|
||||
return db.SuaiUsers.Intersect(attribute, value, db.UneconUsers)
|
||||
}
|
||||
|
||||
func (db *Database) Union() *Table[*User] {
|
||||
return db.SuaiUsers.Union(db.UneconUsers)
|
||||
}
|
||||
|
||||
func (db *Database) Remove(id string, dbType DBType) {
|
||||
switch dbType {
|
||||
case SUAI:
|
||||
db.SuaiUsers.Remove(id)
|
||||
fmt.Println(db.SuaiUsers)
|
||||
case UNECON:
|
||||
db.UneconUsers.Remove(id)
|
||||
fmt.Println(db.UneconUsers)
|
||||
}
|
||||
}
|
||||
|
||||
func (db *Database) ShowDB(dbType DBType) {
|
||||
switch dbType {
|
||||
case SUAI:
|
||||
fmt.Println(db.SuaiUsers)
|
||||
case UNECON:
|
||||
fmt.Println(db.UneconUsers)
|
||||
}
|
||||
}
|
||||
8
part_5/go_database/database/i_attribute.go
Normal file
8
part_5/go_database/database/i_attribute.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package database
|
||||
|
||||
type IAttribute interface {
|
||||
Check(attribute, value string) bool
|
||||
Change(attribute, value string) bool
|
||||
|
||||
String() string
|
||||
}
|
||||
155
part_5/go_database/database/table.go
Normal file
155
part_5/go_database/database/table.go
Normal file
@@ -0,0 +1,155 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Node[T IAttribute] struct {
|
||||
Data T
|
||||
Next *Node[T]
|
||||
}
|
||||
|
||||
type Table[T IAttribute] struct {
|
||||
head *Node[T]
|
||||
tail *Node[T]
|
||||
Title string
|
||||
}
|
||||
|
||||
func NewTable[T IAttribute](title string) *Table[T] {
|
||||
return &Table[T]{Title: title}
|
||||
}
|
||||
|
||||
func (t *Table[T]) First() T {
|
||||
if t.head != nil {
|
||||
return t.head.Data
|
||||
}
|
||||
var zero T
|
||||
return zero
|
||||
}
|
||||
|
||||
func (t *Table[T]) Last() T {
|
||||
if t.tail != nil {
|
||||
return t.tail.Data
|
||||
}
|
||||
var zero T
|
||||
return zero
|
||||
}
|
||||
|
||||
func (t *Table[T]) Contains(data T) bool {
|
||||
user, ok := any(data).(*User)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
temp := t.head
|
||||
for temp != nil {
|
||||
if temp.Data.Check(FieldID, strconv.Itoa(user.ID())) {
|
||||
return true
|
||||
}
|
||||
temp = temp.Next
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (t *Table[T]) Insert(data T) bool {
|
||||
if t.Contains(data) {
|
||||
return false
|
||||
}
|
||||
node := &Node[T]{Data: data}
|
||||
if t.head == nil {
|
||||
t.head = node
|
||||
t.tail = node
|
||||
} else {
|
||||
t.tail.Next = node
|
||||
t.tail = node
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (t *Table[T]) Remove(id string) {
|
||||
var prev *Node[T]
|
||||
curr := t.head
|
||||
|
||||
for curr != nil {
|
||||
if curr.Data.Check("id", id) {
|
||||
if prev == nil {
|
||||
t.head = curr.Next
|
||||
if t.head == nil {
|
||||
t.tail = nil
|
||||
}
|
||||
} else {
|
||||
prev.Next = curr.Next
|
||||
if prev.Next == nil {
|
||||
t.tail = prev
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
prev = curr
|
||||
curr = curr.Next
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Table[T]) Intersect(attribute, value string,
|
||||
other *Table[T]) *Table[T] {
|
||||
|
||||
newTable := NewTable[T](fmt.Sprintf("%s-%s", t.Title, other.Title))
|
||||
|
||||
for temp := t.head; temp != nil; temp = temp.Next {
|
||||
if temp.Data.Check(attribute, value) {
|
||||
newTable.Insert(temp.Data)
|
||||
}
|
||||
}
|
||||
for temp := other.head; temp != nil; temp = temp.Next {
|
||||
if temp.Data.Check(attribute, value) &&
|
||||
!newTable.Contains(temp.Data) {
|
||||
newTable.Insert(temp.Data)
|
||||
}
|
||||
}
|
||||
return newTable
|
||||
}
|
||||
|
||||
func (t *Table[T]) Union(other *Table[T]) *Table[T] {
|
||||
newTable := NewTable[T](fmt.Sprintf("%s-%s", t.Title, other.Title))
|
||||
|
||||
for temp := t.head; temp != nil; temp = temp.Next {
|
||||
newTable.Insert(temp.Data)
|
||||
}
|
||||
for temp := other.head; temp != nil; temp = temp.Next {
|
||||
if !newTable.Contains(temp.Data) {
|
||||
newTable.Insert(temp.Data)
|
||||
}
|
||||
}
|
||||
return newTable
|
||||
}
|
||||
|
||||
func (t *Table[T]) Selection(attribute, value string) *Table[T] {
|
||||
newTable := NewTable[T](t.Title + "-new")
|
||||
|
||||
for temp := t.head; temp != nil; temp = temp.Next {
|
||||
if temp.Data.Check(attribute, value) {
|
||||
newTable.Insert(temp.Data)
|
||||
}
|
||||
}
|
||||
return newTable
|
||||
}
|
||||
|
||||
func (t *Table[T]) ForEach(action func(T)) {
|
||||
for temp := t.head; temp != nil; temp = temp.Next {
|
||||
action(temp.Data)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Table[T]) String() string {
|
||||
var sb strings.Builder
|
||||
sb.WriteString(fmt.Sprintf("%s%s%s\n", strings.Repeat("*", 10),
|
||||
t.Title, strings.Repeat("*", 10)))
|
||||
|
||||
for temp := t.head; temp != nil; temp = temp.Next {
|
||||
sb.WriteString(fmt.Sprintf("%s\n", temp.Data.String()))
|
||||
}
|
||||
|
||||
return sb.String()
|
||||
}
|
||||
132
part_5/go_database/database/user.go
Normal file
132
part_5/go_database/database/user.go
Normal file
@@ -0,0 +1,132 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type AccessLevel = string
|
||||
|
||||
const (
|
||||
Student AccessLevel = "S"
|
||||
Teacher AccessLevel = "T"
|
||||
Admin AccessLevel = "A"
|
||||
)
|
||||
|
||||
func AcsessLevelFromString(s string) AccessLevel {
|
||||
switch strings.ToUpper(s) {
|
||||
case "T":
|
||||
return Teacher
|
||||
case "A":
|
||||
return Admin
|
||||
default:
|
||||
return Student
|
||||
}
|
||||
}
|
||||
|
||||
type UserTableField = string
|
||||
|
||||
const (
|
||||
FieldID UserTableField = "id"
|
||||
FieldNickname UserTableField = "nickname"
|
||||
FieldYearOfBirth UserTableField = "yearOfBirth"
|
||||
FieldEmail UserTableField = "email"
|
||||
FieldPhone UserTableField = "phone"
|
||||
FieldAccessLevel UserTableField = "accessLevel"
|
||||
FieldPasswordHash UserTableField = "passwordHash"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
id int
|
||||
nickname string
|
||||
yearOfBirth int
|
||||
email string
|
||||
phone string
|
||||
accessLevel AccessLevel
|
||||
passwordHash string
|
||||
}
|
||||
|
||||
func NewUser(
|
||||
id int,
|
||||
nickname string,
|
||||
yearOfBirth int,
|
||||
email string,
|
||||
phone string,
|
||||
accessLevel string,
|
||||
passwordHash string,
|
||||
) *User {
|
||||
return &User{
|
||||
id: id,
|
||||
nickname: nickname,
|
||||
yearOfBirth: yearOfBirth,
|
||||
email: email,
|
||||
phone: phone,
|
||||
accessLevel: AcsessLevelFromString(accessLevel),
|
||||
passwordHash: passwordHash,
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) ID() int { return u.id }
|
||||
func (u *User) Nickname() string { return u.nickname }
|
||||
func (u *User) YearOfBirth() int { return u.yearOfBirth }
|
||||
func (u *User) Email() string { return u.email }
|
||||
func (u *User) Phone() string { return u.phone }
|
||||
func (u *User) AccessLevel() string { return u.accessLevel }
|
||||
func (u *User) PasswordHash() string { return u.passwordHash }
|
||||
|
||||
func (u *User) Change(attr, value string) bool {
|
||||
switch attr {
|
||||
case FieldNickname:
|
||||
u.nickname = value
|
||||
case FieldYearOfBirth:
|
||||
v, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
u.yearOfBirth = v
|
||||
case FieldEmail:
|
||||
u.email = value
|
||||
case FieldPhone:
|
||||
u.phone = value
|
||||
case FieldAccessLevel:
|
||||
u.accessLevel = AcsessLevelFromString(value)
|
||||
case FieldPasswordHash:
|
||||
u.passwordHash = value
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (u *User) Check(attr, value string) bool {
|
||||
switch attr {
|
||||
case FieldID:
|
||||
v, err := strconv.Atoi(value)
|
||||
return err == nil && u.id == v
|
||||
case FieldNickname:
|
||||
return u.nickname == value
|
||||
case FieldYearOfBirth:
|
||||
v, err := strconv.Atoi(value)
|
||||
return err == nil && u.yearOfBirth == v
|
||||
case FieldEmail:
|
||||
return u.email == value
|
||||
case FieldPhone:
|
||||
return u.phone == value
|
||||
case FieldAccessLevel:
|
||||
return u.accessLevel == value
|
||||
case FieldPasswordHash:
|
||||
return u.passwordHash == value
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) String() string {
|
||||
return fmt.Sprintf(
|
||||
"User(id: %d, nickname: %s, yearOfBirth: %d, "+
|
||||
"email: %s, phone: %s, acsessLevel: %s, passwordHash: %s)",
|
||||
u.id, u.nickname, u.yearOfBirth, u.email,
|
||||
u.phone, u.accessLevel, u.passwordHash,
|
||||
)
|
||||
}
|
||||
3
part_5/go_database/go.mod
Normal file
3
part_5/go_database/go.mod
Normal file
@@ -0,0 +1,3 @@
|
||||
module go_database
|
||||
|
||||
go 1.24
|
||||
16
part_5/go_database/main.go
Normal file
16
part_5/go_database/main.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
db "go_database/database"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func main() {
|
||||
db := db.NewDatabase(
|
||||
filepath.Join(".", "suai.txt"),
|
||||
filepath.Join(".", "unecon.txt"),
|
||||
)
|
||||
|
||||
menu := NewMenu(db)
|
||||
menu.Loop()
|
||||
}
|
||||
214
part_5/go_database/menu.go
Normal file
214
part_5/go_database/menu.go
Normal file
@@ -0,0 +1,214 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
db "go_database/database"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Menu struct {
|
||||
database *db.Database
|
||||
reader *bufio.Reader
|
||||
}
|
||||
|
||||
func NewMenu(db *db.Database) *Menu {
|
||||
return &Menu{
|
||||
database: db,
|
||||
reader: bufio.NewReader(os.Stdin),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Menu) Loop() {
|
||||
for {
|
||||
m.PrintMenu()
|
||||
input, _ := m.reader.ReadString('\n')
|
||||
input = strings.TrimSpace(input)
|
||||
|
||||
fmt.Println(strings.Repeat("x", 25))
|
||||
|
||||
switch input {
|
||||
case "1":
|
||||
m.AddUser()
|
||||
case "2":
|
||||
m.RemoveUser()
|
||||
case "3":
|
||||
m.ChangeUser()
|
||||
case "4":
|
||||
m.ShowUsers()
|
||||
case "5":
|
||||
m.Intersect()
|
||||
case "6":
|
||||
m.Union()
|
||||
case "7":
|
||||
m.SaveAndExit()
|
||||
return
|
||||
case "8":
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Menu) PrintMenu() {
|
||||
fmt.Println("1. Add User")
|
||||
fmt.Println("2. Remove User")
|
||||
fmt.Println("3. Change User")
|
||||
fmt.Println("4. Show Users")
|
||||
fmt.Println("5. Intersect Table")
|
||||
fmt.Println("6. Union Table")
|
||||
fmt.Println("7. Save and Exit")
|
||||
fmt.Println("8. Exit")
|
||||
}
|
||||
|
||||
func (m *Menu) readInput(prompt string) string {
|
||||
fmt.Print(prompt)
|
||||
input, _ := m.reader.ReadString('\n')
|
||||
return strings.TrimSpace(input)
|
||||
}
|
||||
|
||||
func (m *Menu) AddUser() {
|
||||
try := func() bool {
|
||||
idStr := m.readInput("Enter id: ")
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil {
|
||||
fmt.Println("Invalid ID format")
|
||||
return false
|
||||
}
|
||||
|
||||
nickname := m.readInput("Enter nickname: ")
|
||||
|
||||
yearStr := m.readInput("Enter year of birth: ")
|
||||
yearOfBirth, err := strconv.Atoi(yearStr)
|
||||
if err != nil {
|
||||
fmt.Println("Invalid year format")
|
||||
return false
|
||||
}
|
||||
|
||||
email := m.readInput("Enter email: ")
|
||||
phone := m.readInput("Enter phone: ")
|
||||
passwordHash := m.readInput("Enter password hash: ")
|
||||
accessLevel := m.readInput("Access level (A - Admin, " +
|
||||
"T - Teacher, S - Student): ")
|
||||
|
||||
user := db.NewUser(
|
||||
id,
|
||||
nickname,
|
||||
yearOfBirth,
|
||||
email,
|
||||
phone,
|
||||
accessLevel,
|
||||
passwordHash,
|
||||
)
|
||||
|
||||
dbTypeStr := m.readInput("Add user to DB (S - SUAI, U - Unecon): ")
|
||||
dbTypeStr = strings.ToUpper(dbTypeStr)
|
||||
|
||||
switch dbTypeStr {
|
||||
case "S":
|
||||
m.database.Insert(user, db.SUAI)
|
||||
m.database.ShowDB(db.SUAI)
|
||||
case "U":
|
||||
m.database.Insert(user, db.UNECON)
|
||||
m.database.ShowDB(db.UNECON)
|
||||
default:
|
||||
fmt.Println("(ノ-_-)ノ ミ ┴┴")
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
if !try() {
|
||||
fmt.Println("WTF!!!!")
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Menu) RemoveUser() {
|
||||
dbTypeStr := m.readInput("Select DB (S - SUAI, U - Unecon): ")
|
||||
dbTypeStr = strings.ToUpper(dbTypeStr)
|
||||
|
||||
var dbType db.DBType
|
||||
|
||||
switch dbTypeStr {
|
||||
case "S":
|
||||
dbType = db.SUAI
|
||||
m.database.ShowDB(db.SUAI)
|
||||
case "U":
|
||||
dbType = db.UNECON
|
||||
m.database.ShowDB(db.UNECON)
|
||||
default:
|
||||
fmt.Println("(ノ-_-)ノ ミ ┴┴")
|
||||
return
|
||||
}
|
||||
|
||||
id := m.readInput("Enter id: ")
|
||||
m.database.Remove(id, dbType)
|
||||
m.database.ShowDB(dbType)
|
||||
}
|
||||
|
||||
func (m *Menu) ChangeUser() {
|
||||
dbTypeStr := m.readInput("Select DB (S - SUAI, U - Unecon): ")
|
||||
dbTypeStr = strings.ToUpper(dbTypeStr)
|
||||
|
||||
var dbType db.DBType
|
||||
|
||||
switch dbTypeStr {
|
||||
case "S":
|
||||
dbType = db.SUAI
|
||||
m.database.ShowDB(db.SUAI)
|
||||
case "U":
|
||||
dbType = db.UNECON
|
||||
m.database.ShowDB(db.UNECON)
|
||||
default:
|
||||
fmt.Println("(ノ-_-)ノ ミ ┴┴")
|
||||
return
|
||||
}
|
||||
|
||||
id := m.readInput("Enter id: ")
|
||||
|
||||
userTable := m.database.Selection(dbType, "id", id)
|
||||
user := userTable.First()
|
||||
if user == nil {
|
||||
fmt.Println("User not found!")
|
||||
return
|
||||
}
|
||||
|
||||
field := m.readInput("Enter field: ")
|
||||
newValue := m.readInput("Enter new value: ")
|
||||
user.Change(field, newValue)
|
||||
|
||||
m.database.ShowDB(dbType)
|
||||
}
|
||||
|
||||
func (m *Menu) ShowUsers() {
|
||||
dbTypeStr := m.readInput("Select DB (S - SUAI, U - Unecon): ")
|
||||
dbTypeStr = strings.ToUpper(dbTypeStr)
|
||||
|
||||
switch dbTypeStr {
|
||||
case "S":
|
||||
m.database.ShowDB(db.SUAI)
|
||||
case "U":
|
||||
m.database.ShowDB(db.UNECON)
|
||||
default:
|
||||
fmt.Println("(ノ-_-)ノ ミ ┴┴")
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Menu) Intersect() {
|
||||
field := m.readInput("Enter field: ")
|
||||
value := m.readInput("Enter intersect value: ")
|
||||
result := m.database.Intersect(field, value)
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
func (m *Menu) Union() {
|
||||
result := m.database.Union()
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
func (m *Menu) SaveAndExit() {
|
||||
m.database.Save(db.SUAI)
|
||||
m.database.Save(db.UNECON)
|
||||
}
|
||||
5
part_5/go_database/suai.txt
Normal file
5
part_5/go_database/suai.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
0,MADTeacher,1989,stasko@gmail.ru,+7xxxxxxx,T,adFF
|
||||
1,Alex,1990,al@gmail.ru,+7x2x5xxx,A,adadFFxzxc
|
||||
2,Max,2005,mmm@gmail.ru,+7xx654xx,S,20AFBB
|
||||
3,Jack,2006,jj@gmail.ru,+7xx657xx,S,41FDF
|
||||
5,FF,1999,mad@tr.ri,+7xx654xx,S,Hdndgu2397123
|
||||
4
part_5/go_database/unecon.txt
Normal file
4
part_5/go_database/unecon.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
0,Jack,2007,gf@gmail.ru,+7xx624xx,S,20AAAB
|
||||
1,MADTeacher,1989,stasko@gmail.ru,+7xxxxxxx,T,adFF
|
||||
2,Stas,1994,st@gmail.ru,+7x2x2xxx,A,adaFBB
|
||||
6,Max,2009,mv@gmail.ru,+7xx657xx,S,41FDF
|
||||
3
part_5/go_json_store/go.mod
Normal file
3
part_5/go_json_store/go.mod
Normal file
@@ -0,0 +1,3 @@
|
||||
module go_json_store
|
||||
|
||||
go 1.20
|
||||
62
part_5/go_json_store/jsonstore/json_file.go
Normal file
62
part_5/go_json_store/jsonstore/json_file.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package jsonstore
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
type JSONFile struct {
|
||||
Path string
|
||||
}
|
||||
|
||||
func NewJSONFile(path string) *JSONFile {
|
||||
dir := filepath.Dir(path)
|
||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||
os.MkdirAll(dir, 0755)
|
||||
}
|
||||
return &JSONFile{Path: path}
|
||||
}
|
||||
|
||||
func (j *JSONFile) Read() map[string]any {
|
||||
file, err := os.Open(j.Path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return make(map[string]any)
|
||||
}
|
||||
return make(map[string]any)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
data, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
return make(map[string]any)
|
||||
}
|
||||
|
||||
if len(data) == 0 {
|
||||
return make(map[string]any)
|
||||
}
|
||||
|
||||
var result map[string]any
|
||||
err = json.Unmarshal(data, &result)
|
||||
if err != nil {
|
||||
return make(map[string]any)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (j *JSONFile) Write(data map[string]any) error {
|
||||
dir := filepath.Dir(j.Path)
|
||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||
os.MkdirAll(dir, 0755)
|
||||
}
|
||||
|
||||
jsonData, err := json.MarshalIndent(data, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return os.WriteFile(j.Path, jsonData, 0644)
|
||||
}
|
||||
200
part_5/go_json_store/jsonstore/json_store.go
Normal file
200
part_5/go_json_store/jsonstore/json_store.go
Normal file
@@ -0,0 +1,200 @@
|
||||
package jsonstore
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type JSONStore struct {
|
||||
filePath string
|
||||
values map[string]interface{}
|
||||
}
|
||||
|
||||
func NewJSONStore(path string) *JSONStore {
|
||||
return &JSONStore{
|
||||
filePath: path,
|
||||
}
|
||||
}
|
||||
|
||||
func (js *JSONStore) load() map[string]interface{} {
|
||||
if js.values != nil {
|
||||
return js.values
|
||||
}
|
||||
|
||||
content, err := os.ReadFile(js.filePath)
|
||||
if err != nil {
|
||||
js.values = make(map[string]interface{})
|
||||
return js.values
|
||||
}
|
||||
|
||||
var data map[string]interface{}
|
||||
if err := json.Unmarshal(content, &data); err != nil {
|
||||
js.values = make(map[string]interface{})
|
||||
return js.values
|
||||
}
|
||||
js.values = data
|
||||
return js.values
|
||||
}
|
||||
|
||||
func (js *JSONStore) Contains(key string) bool {
|
||||
_, ok := js.load()[key]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (js *JSONStore) Keys() []string {
|
||||
keys := make([]string, 0)
|
||||
for k := range js.load() {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
func (js *JSONStore) Values() []interface{} {
|
||||
values := make([]interface{}, 0)
|
||||
for _, v := range js.load() {
|
||||
values = append(values, v)
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
func (js *JSONStore) GetValue(key string) interface{} {
|
||||
return js.load()[key]
|
||||
}
|
||||
|
||||
func (js *JSONStore) GetBool(key string) *bool {
|
||||
if v, ok := js.GetValue(key).(bool); ok {
|
||||
return &v
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (js *JSONStore) GetInt(key string) *int {
|
||||
// Т.к. все числа по умолчанию декодируются как float64,
|
||||
// то сначала приводим к float64
|
||||
if f, ok := js.GetValue(key).(float64); ok {
|
||||
i := int(f)
|
||||
return &i
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (js *JSONStore) GetFloat(key string) *float64 {
|
||||
if v, ok := js.GetValue(key).(float64); ok {
|
||||
return &v
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (js *JSONStore) GetString(key string) *string {
|
||||
if v, ok := js.GetValue(key).(string); ok {
|
||||
return &v
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Метод возвращает по ключу срез []interface{}.
|
||||
// Если значение хранится как []interface{}, возвращаем его напрямую.
|
||||
// Если значение хранится как []string, []int или []float64,
|
||||
// преобразуем каждый элемент к interface{} для совместимости
|
||||
// с Go JSON API. Это обеспечивает универсальный доступ к массивам
|
||||
// любого типа, сохраненным в JSON.
|
||||
func (js *JSONStore) GetList(key string) []interface{} {
|
||||
// Получаем значение по ключу
|
||||
val := js.GetValue(key)
|
||||
// Если значение отсутствует, возвращаем nil
|
||||
if val == nil {
|
||||
return nil
|
||||
}
|
||||
// Если это уже []interface{} (тип, который возвращает
|
||||
// json.Unmarshal), возвращаем напрямую
|
||||
if v, ok := val.([]interface{}); ok {
|
||||
return v
|
||||
}
|
||||
// Если это []string, преобразуем каждый элемент к interface{}
|
||||
if v, ok := val.([]string); ok {
|
||||
// Создаем новый срез с типом []interface{}
|
||||
result := make([]interface{}, len(v))
|
||||
// Преобразуем каждый элемент []string в interface{}
|
||||
for i, s := range v {
|
||||
result[i] = s
|
||||
}
|
||||
return result
|
||||
}
|
||||
// Если это []int, преобразуем каждый элемент к interface{}
|
||||
if v, ok := val.([]int); ok {
|
||||
// Создаем новый срез с типом []interface{}
|
||||
result := make([]interface{}, len(v))
|
||||
// Преобразуем каждый элемент []int в interface{}
|
||||
for i, n := range v {
|
||||
result[i] = n
|
||||
}
|
||||
return result
|
||||
}
|
||||
// Если это []float64 (тип, который возвращает json.Unmarshal),
|
||||
// преобразуем каждый элемент к interface{}
|
||||
if v, ok := val.([]float64); ok {
|
||||
// Создаем новый срез с типом []interface{}
|
||||
result := make([]interface{}, len(v))
|
||||
// Преобразуем каждый элемент []float64 в interface{}
|
||||
for i, n := range v {
|
||||
result[i] = n
|
||||
}
|
||||
return result
|
||||
}
|
||||
// Если тип не поддерживается, возвращаем nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (js *JSONStore) GetMap(key string) map[string]interface{} {
|
||||
val := js.GetValue(key)
|
||||
if val == nil {
|
||||
return nil
|
||||
}
|
||||
if m, ok := val.(map[string]interface{}); ok {
|
||||
return m
|
||||
}
|
||||
// Попробуем привести через json, если тип не совпал
|
||||
if b, err := json.Marshal(val); err == nil {
|
||||
var m map[string]interface{}
|
||||
if err := json.Unmarshal(b, &m); err == nil {
|
||||
return m
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (js *JSONStore) ValueEquals(a, b interface{}) bool {
|
||||
return reflect.DeepEqual(a, b)
|
||||
}
|
||||
|
||||
func (js *JSONStore) SetValue(key string, value interface{}) {
|
||||
|
||||
values := js.load()
|
||||
oldVal := values[key]
|
||||
if value == nil {
|
||||
delete(values, key)
|
||||
js.save(values)
|
||||
} else if oldVal == nil || !js.ValueEquals(oldVal, value) {
|
||||
values[key] = value
|
||||
js.save(values)
|
||||
}
|
||||
}
|
||||
|
||||
func (js *JSONStore) ResetValue(key string) {
|
||||
|
||||
values := js.load()
|
||||
if _, exists := values[key]; exists {
|
||||
delete(values, key)
|
||||
js.save(values)
|
||||
}
|
||||
}
|
||||
|
||||
func (js *JSONStore) save(data map[string]interface{}) {
|
||||
bytes, err := json.MarshalIndent(data, "", " ")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_ = os.WriteFile(js.filePath, bytes, 0644)
|
||||
js.values = data
|
||||
}
|
||||
167
part_5/go_json_store/main.go
Normal file
167
part_5/go_json_store/main.go
Normal file
@@ -0,0 +1,167 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"go_json_store/jsonstore"
|
||||
)
|
||||
|
||||
func main() {
|
||||
store := jsonstore.NewJSONStore("store.json")
|
||||
store.SetValue("map", map[string]int{"a": 1, "b": 2})
|
||||
store.SetValue("strList", []string{"a", "b", "c"})
|
||||
store.SetValue("intList", []int{1, 2, 3})
|
||||
|
||||
// Получение и приведение типов
|
||||
rawStrList := store.GetList("strList")
|
||||
var strList []string
|
||||
for _, v := range rawStrList {
|
||||
if s, ok := v.(string); ok {
|
||||
strList = append(strList, s)
|
||||
}
|
||||
}
|
||||
|
||||
rawIntList := store.GetList("intList")
|
||||
var intList []int
|
||||
for _, v := range rawIntList {
|
||||
if n, ok := v.(int); ok {
|
||||
intList = append(intList, n)
|
||||
}
|
||||
}
|
||||
|
||||
rawMap := store.GetMap("map")
|
||||
myMap := make(map[string]int)
|
||||
for k, v := range rawMap {
|
||||
switch n := v.(type) {
|
||||
case int:
|
||||
myMap[k] = n
|
||||
case float64:
|
||||
myMap[k] = int(n)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("%T\n", strList) // []string
|
||||
fmt.Printf("%T\n", intList) // []int
|
||||
fmt.Printf("%T\n", myMap) // map[string]int
|
||||
|
||||
fmt.Println(strList) // [a b c]
|
||||
fmt.Println(intList) // [1 2 3]
|
||||
fmt.Println(myMap) // map[a:1 b:2]
|
||||
|
||||
boolVal := store.GetBool("bool")
|
||||
fmt.Println(*boolVal) // true
|
||||
intVal := store.GetInt("int")
|
||||
fmt.Println(*intVal) // 55
|
||||
floatVal := store.GetFloat("double")
|
||||
fmt.Println(*floatVal) // 99.4
|
||||
}
|
||||
|
||||
//*************** 3 ***************************
|
||||
/*
|
||||
func main() {
|
||||
store := jsonstore.NewJSONStore("store.json")
|
||||
|
||||
store.ResetValue("map")
|
||||
store.ResetValue("str")
|
||||
|
||||
fmt.Println(store.GetValue("map")) // <nil>
|
||||
fmt.Println(store.GetValue("str")) // <nil>
|
||||
}
|
||||
*/
|
||||
|
||||
//*************** 2 ***************************
|
||||
/*
|
||||
func main() {
|
||||
store := jsonstore.NewJSONStore("store.json")
|
||||
|
||||
store.SetValue("strList", "-_-")
|
||||
store.SetValue("double", 99)
|
||||
|
||||
fmt.Println(store.GetValue("strList")) // -_-
|
||||
fmt.Println(store.GetValue("double")) // 99
|
||||
}
|
||||
*/
|
||||
|
||||
//*************** 1 ***************************
|
||||
/*
|
||||
func main() {
|
||||
store := jsonstore.NewJSONStore("store.json")
|
||||
store.SetValue("strList", []string{"a", "b", "c"})
|
||||
store.SetValue("int", 55)
|
||||
store.SetValue("bool", true)
|
||||
store.SetValue("double", 3.14)
|
||||
store.SetValue("map", map[string]int{"a": 1, "b": 2})
|
||||
store.SetValue("str", "(づ˶•༝•˶)づ♡")
|
||||
|
||||
fmt.Println(store.Values())
|
||||
// [[a b c] 55 true 3.14 map[a:1 b:2] (づ˶•༝•˶)づ♡]
|
||||
|
||||
fmt.Println(store.Keys())
|
||||
// [bool double map str strList int]
|
||||
|
||||
fmt.Println(store.Contains("strList")) // true
|
||||
fmt.Println(store.GetValue("strList")) // [a b c]
|
||||
fmt.Println(store.GetValue("int")) // 55
|
||||
fmt.Println(store.GetValue("bool")) // true
|
||||
fmt.Println(store.GetValue("double")) // 3.14
|
||||
fmt.Println(store.GetValue("map")) // map[a:1 b:2]
|
||||
fmt.Println(store.GetValue("str")) // (づ˶•༝•˶)づ♡
|
||||
} */
|
||||
|
||||
/*func main() {
|
||||
fmt.Println("Starting JSON Store Demo")
|
||||
store := jsonstore.NewJSONStore("store.json")
|
||||
|
||||
// Set some values
|
||||
mapValue := map[string]any{"a": 1, "b": 2}
|
||||
strList := []any{"a", "b", "c"}
|
||||
intList := []any{1, 2, 3}
|
||||
|
||||
store.SetValue("map", mapValue)
|
||||
store.SetValue("strList", strList)
|
||||
store.SetValue("intList", intList)
|
||||
|
||||
// Get values
|
||||
retrievedStrList := store.GetList("strList")
|
||||
retrievedIntList := store.GetList("intList")
|
||||
retrievedMap := store.GetMap("map")
|
||||
|
||||
// Print results
|
||||
fmt.Printf("strList type: %T\n", retrievedStrList)
|
||||
fmt.Printf("intList type: %T\n", retrievedIntList)
|
||||
fmt.Printf("map type: %T\n", retrievedMap)
|
||||
|
||||
fmt.Printf("strList: %v\n", retrievedStrList)
|
||||
fmt.Printf("intList: %v\n", retrievedIntList)
|
||||
fmt.Printf("map: %v\n", retrievedMap)
|
||||
|
||||
// Let's demonstrate more features similar to the commented section in the Dart code
|
||||
store.SetValue("int", 55)
|
||||
store.SetValue("bool", true)
|
||||
store.SetValue("double", 3.14)
|
||||
store.SetValue("str", "(づ˶•༝•˶)づ♡")
|
||||
|
||||
fmt.Println("\nAll values:", store.Values())
|
||||
fmt.Println("All keys:", store.Keys())
|
||||
|
||||
fmt.Printf("Contains 'strList': %v\n", store.Contains("strList"))
|
||||
fmt.Printf("Value of 'strList': %v\n", store.GetValue("strList"))
|
||||
fmt.Printf("Value of 'int': %v\n", store.GetValue("int"))
|
||||
fmt.Printf("Value of 'bool': %v\n", store.GetValue("bool"))
|
||||
fmt.Printf("Value of 'double': %v\n", store.GetValue("double"))
|
||||
fmt.Printf("Value of 'map': %v\n", store.GetValue("map"))
|
||||
fmt.Printf("Value of 'str': %v\n", store.GetValue("str"))
|
||||
|
||||
// Update values
|
||||
store.SetValue("strList", "-_-")
|
||||
store.SetValue("double", 99)
|
||||
fmt.Printf("\nUpdated 'strList': %v\n", store.GetValue("strList"))
|
||||
fmt.Printf("Updated 'double': %v\n", store.GetValue("double"))
|
||||
|
||||
// Reset values
|
||||
store.ResetValue("map")
|
||||
store.ResetValue("str")
|
||||
fmt.Printf("After reset, 'map': %v\n", store.GetValue("map"))
|
||||
fmt.Printf("After reset, 'str': %v\n", store.GetValue("str"))
|
||||
}
|
||||
*/
|
||||
19
part_5/go_json_store/store.json
Normal file
19
part_5/go_json_store/store.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"bool": true,
|
||||
"double": 99.4,
|
||||
"int": 55,
|
||||
"intList": [
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"map": {
|
||||
"a": 1,
|
||||
"b": 2
|
||||
},
|
||||
"strList": [
|
||||
"a",
|
||||
"b",
|
||||
"c"
|
||||
]
|
||||
}
|
||||
14
part_5/tic_tac_toe/.vscode/launch.json
vendored
Normal file
14
part_5/tic_tac_toe/.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
{
|
||||
"name": "Launch Package",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "auto",
|
||||
"program": "${fileDirname}", // <- ставим запятую
|
||||
"console": "integratedTerminal"
|
||||
}
|
||||
]
|
||||
}
|
||||
113
part_5/tic_tac_toe/game/board.go
Normal file
113
part_5/tic_tac_toe/game/board.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
BoardDefaultSize int = 3
|
||||
BoardMinSize int = 3
|
||||
BoardMaxSize int = 9
|
||||
)
|
||||
|
||||
type Board struct {
|
||||
Board [][]BoardField `json:"board"`
|
||||
Size int `json:"size"`
|
||||
}
|
||||
|
||||
func NewBoard(size int) *Board {
|
||||
board := make([][]BoardField, size)
|
||||
for i := range board {
|
||||
board[i] = make([]BoardField, size)
|
||||
}
|
||||
return &Board{Board: board, Size: size}
|
||||
}
|
||||
|
||||
// Отображение игрового поля
|
||||
func (b *Board) printBoard() {
|
||||
fmt.Print(" ")
|
||||
for i := range b.Size {
|
||||
fmt.Printf("%d ", i+1)
|
||||
}
|
||||
fmt.Println()
|
||||
for i := range b.Size {
|
||||
fmt.Printf("%d ", i+1)
|
||||
for j := range b.Size {
|
||||
switch b.Board[i][j] {
|
||||
case empty:
|
||||
fmt.Print(". ")
|
||||
case cross:
|
||||
fmt.Print("X ")
|
||||
case nought:
|
||||
fmt.Print("O ")
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
// Проверка возможности и выполнения хода
|
||||
func (b *Board) makeMove(x, y int) bool {
|
||||
return b.Board[x][y] == empty
|
||||
}
|
||||
|
||||
func (b *Board) setSymbol(x, y int, player BoardField) bool {
|
||||
if b.makeMove(x, y) {
|
||||
b.Board[x][y] = player
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Проверка выигрыша
|
||||
func (b *Board) checkWin(player BoardField) bool {
|
||||
// Проверка строк и столбцов
|
||||
for i := range b.Size {
|
||||
rowWin, colWin := true, true
|
||||
for j := range b.Size {
|
||||
if b.Board[i][j] != player {
|
||||
rowWin = false
|
||||
}
|
||||
if b.Board[j][i] != player {
|
||||
colWin = false
|
||||
}
|
||||
}
|
||||
if rowWin || colWin {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Главная диагональ
|
||||
mainDiag := true
|
||||
for i := range b.Size {
|
||||
if b.Board[i][i] != player {
|
||||
mainDiag = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if mainDiag {
|
||||
return true
|
||||
}
|
||||
|
||||
// Побочная диагональ
|
||||
antiDiag := true
|
||||
for i := range b.Size {
|
||||
if b.Board[i][b.Size-i-1] != player {
|
||||
antiDiag = false
|
||||
break
|
||||
}
|
||||
}
|
||||
return antiDiag
|
||||
}
|
||||
|
||||
// Проверка на ничью
|
||||
func (b *Board) checkDraw() bool {
|
||||
for i := range b.Size {
|
||||
for j := range b.Size {
|
||||
if b.Board[i][j] == empty {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
10
part_5/tic_tac_toe/game/board_cell_type.go
Normal file
10
part_5/tic_tac_toe/game/board_cell_type.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package game
|
||||
|
||||
type BoardField int
|
||||
|
||||
// фигуры в клетке поля
|
||||
const (
|
||||
empty BoardField = iota
|
||||
cross
|
||||
nought
|
||||
)
|
||||
122
part_5/tic_tac_toe/game/game.go
Normal file
122
part_5/tic_tac_toe/game/game.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Game struct {
|
||||
Board *Board `json:"board"`
|
||||
Player *Player `json:"player"`
|
||||
Reader *bufio.Reader `json:"-"`
|
||||
State GameState `json:"state"`
|
||||
Saver IGameSaver `json:"-"`
|
||||
}
|
||||
|
||||
func NewGame(board Board, player Player,
|
||||
reader *bufio.Reader, saver IGameSaver) *Game {
|
||||
return &Game{
|
||||
Board: &board,
|
||||
Player: &player,
|
||||
Reader: reader,
|
||||
State: playing,
|
||||
Saver: saver,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Game) updateState() {
|
||||
if g.Board.checkWin(g.Player.Figure) {
|
||||
if g.Player.Figure == cross {
|
||||
g.State = crossWin
|
||||
} else {
|
||||
g.State = noughtWin
|
||||
}
|
||||
} else if g.Board.checkDraw() {
|
||||
g.State = draw
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Game) saveCheck(input string) bool {
|
||||
if input == "save" {
|
||||
fmt.Println("Enter file name: ")
|
||||
fileName, err := g.Reader.ReadString('\n')
|
||||
if err != nil {
|
||||
fmt.Println("Invalid input. Please try again.")
|
||||
return false
|
||||
}
|
||||
|
||||
fileName = strings.TrimSpace(fileName)
|
||||
err = g.Saver.SaveGame(fileName, g)
|
||||
if err != nil {
|
||||
fmt.Println("Error saving game.")
|
||||
return false
|
||||
}
|
||||
fmt.Println("Game saved successfully!!!")
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Игровой цикл
|
||||
func (g *Game) Play() {
|
||||
for g.State == playing {
|
||||
g.Board.printBoard()
|
||||
fmt.Printf(
|
||||
"%s's turn. Enter row and column (e.g. 1 2): ",
|
||||
g.Player.getSymbol())
|
||||
|
||||
input, err := g.Reader.ReadString('\n')
|
||||
input = strings.TrimSpace(input)
|
||||
if err != nil {
|
||||
fmt.Println("Invalid input. Please try again.")
|
||||
continue
|
||||
}
|
||||
|
||||
input = strings.TrimSpace(input)
|
||||
if input == "q" {
|
||||
g.State = quit
|
||||
break
|
||||
}
|
||||
|
||||
if g.saveCheck(input) {
|
||||
continue
|
||||
}
|
||||
|
||||
parts := strings.Fields(input)
|
||||
if len(parts) != 2 {
|
||||
fmt.Println("Invalid input. Please try again.")
|
||||
continue
|
||||
}
|
||||
|
||||
row, err1 := strconv.Atoi(parts[0])
|
||||
col, err2 := strconv.Atoi(parts[1])
|
||||
if err1 != nil || err2 != nil ||
|
||||
row < 1 || col < 1 || row > g.Board.Size ||
|
||||
col > g.Board.Size {
|
||||
fmt.Println("Invalid input. Please try again.")
|
||||
continue
|
||||
}
|
||||
if g.Board.setSymbol(row-1, col-1, g.Player.Figure) {
|
||||
g.updateState()
|
||||
g.Player.switchPlayer()
|
||||
|
||||
} else {
|
||||
fmt.Println("This cell is already occupied!")
|
||||
}
|
||||
}
|
||||
|
||||
g.Board.printBoard()
|
||||
|
||||
if g.State == crossWin {
|
||||
fmt.Println("X wins!")
|
||||
} else if g.State == noughtWin {
|
||||
fmt.Println("O wins!")
|
||||
} else if g.State == draw {
|
||||
fmt.Println("It's a draw!")
|
||||
} else {
|
||||
fmt.Println("Game over!")
|
||||
}
|
||||
}
|
||||
12
part_5/tic_tac_toe/game/game_state.go
Normal file
12
part_5/tic_tac_toe/game/game_state.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package game
|
||||
|
||||
type GameState int
|
||||
|
||||
// состояние игрового процесса
|
||||
const (
|
||||
playing GameState = iota
|
||||
draw
|
||||
crossWin
|
||||
noughtWin
|
||||
quit
|
||||
)
|
||||
9
part_5/tic_tac_toe/game/i_game_loader.go
Normal file
9
part_5/tic_tac_toe/game/i_game_loader.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package game
|
||||
|
||||
type IGameLoader interface {
|
||||
LoadGame(path string) (*Game, error)
|
||||
}
|
||||
|
||||
type IGameSaver interface {
|
||||
SaveGame(path string, game *Game) error
|
||||
}
|
||||
50
part_5/tic_tac_toe/game/json_game_loader.go
Normal file
50
part_5/tic_tac_toe/game/json_game_loader.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func NewJsonGameLoader() IGameLoader {
|
||||
return &JsonGameLoader{}
|
||||
}
|
||||
|
||||
type JsonGameLoader struct{}
|
||||
|
||||
func (j *JsonGameLoader) LoadGame(path string) (*Game, error) {
|
||||
if !strings.HasSuffix(path, ".json") {
|
||||
path += ".json"
|
||||
}
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
decoder := json.NewDecoder(file)
|
||||
var game Game
|
||||
err = decoder.Decode(&game)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &game, nil
|
||||
}
|
||||
|
||||
func (j *JsonGameLoader) SaveGame(path string, game *Game) error {
|
||||
if !strings.HasSuffix(path, ".json") {
|
||||
path += ".json"
|
||||
}
|
||||
file, err := os.Create(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
encoder := json.NewEncoder(file)
|
||||
err = encoder.Encode(game)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
24
part_5/tic_tac_toe/game/player.go
Normal file
24
part_5/tic_tac_toe/game/player.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package game
|
||||
|
||||
type Player struct {
|
||||
Figure BoardField `json:"figure"`
|
||||
}
|
||||
|
||||
func NewPlayer() *Player {
|
||||
return &Player{Figure: cross}
|
||||
}
|
||||
|
||||
func (p *Player) switchPlayer() {
|
||||
if p.Figure == cross {
|
||||
p.Figure = nought
|
||||
} else {
|
||||
p.Figure = cross
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Player) getSymbol() string {
|
||||
if p.Figure == cross {
|
||||
return "X"
|
||||
}
|
||||
return "O"
|
||||
}
|
||||
3
part_5/tic_tac_toe/go.mod
Normal file
3
part_5/tic_tac_toe/go.mod
Normal file
@@ -0,0 +1,3 @@
|
||||
module tic-tac-toe
|
||||
|
||||
go 1.24.0
|
||||
76
part_5/tic_tac_toe/main.go
Normal file
76
part_5/tic_tac_toe/main.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"tic-tac-toe/game"
|
||||
)
|
||||
|
||||
func main() {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
loader := game.NewJsonGameLoader()
|
||||
boardSize := 0
|
||||
|
||||
for {
|
||||
fmt.Println("1 - load game")
|
||||
fmt.Println("2 - new game")
|
||||
fmt.Println("q - quit")
|
||||
|
||||
input, _ := reader.ReadString('\n')
|
||||
input = strings.TrimSpace(input)
|
||||
switch input {
|
||||
case "1":
|
||||
var loadedGame *game.Game
|
||||
var err error
|
||||
for {
|
||||
fmt.Println("Enter file name: ")
|
||||
fileName, _ := reader.ReadString('\n')
|
||||
fileName = strings.TrimSpace(fileName)
|
||||
loadedGame, err = loader.LoadGame(fileName)
|
||||
if err != nil {
|
||||
fmt.Println("Error loading game.")
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
loadedGame.Reader = reader
|
||||
loadedGame.Saver = loader.(game.IGameSaver)
|
||||
loadedGame.Play()
|
||||
case "2":
|
||||
for {
|
||||
fmt.Print("Enter the size of the board (3-9): ")
|
||||
input, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
fmt.Println("Error reading input.")
|
||||
continue
|
||||
}
|
||||
input = strings.TrimSpace(input)
|
||||
boardSize, err = strconv.Atoi(input)
|
||||
if err != nil {
|
||||
// Использовать предыдущий размер по умолчанию
|
||||
boardSize = game.BoardDefaultSize
|
||||
}
|
||||
if boardSize < game.BoardMinSize ||
|
||||
boardSize > game.BoardMaxSize {
|
||||
fmt.Println("Invalid board size.")
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
board := game.NewBoard(boardSize)
|
||||
player := game.NewPlayer()
|
||||
game := game.NewGame(*board, *player, reader,
|
||||
loader.(game.IGameSaver))
|
||||
game.Play()
|
||||
case "q":
|
||||
return
|
||||
default:
|
||||
fmt.Println("Invalid input. Please try again.")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
1
part_5/tic_tac_toe/myGame.json
Normal file
1
part_5/tic_tac_toe/myGame.json
Normal file
@@ -0,0 +1 @@
|
||||
{"board":{"board":[[0,2,0,0],[0,0,1,0],[0,0,0,0],[0,0,1,0]],"size":4},"player":{"figure":2},"state":0}
|
||||
Reference in New Issue
Block a user