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

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

BIN
lessons/strings/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,30 @@
package main
import (
"fmt"
"testing"
)
var result string
func Concat(b *testing.B) {
for i := 0; i < b.N; i++ {
result = "Hello" + " world"
}
}
func Conversion(b *testing.B) {
for i := 0; i < b.N; i++ {
result = string([]byte("Hello world"))
}
}
func main() {
b1 := testing.Benchmark(Concat)
fmt.Println("b1:", b1.AllocsPerOp()) // 0
fmt.Println("b1:", b1.AllocedBytesPerOp()) // 0
b2 := testing.Benchmark(Conversion)
fmt.Println("b2:", b2.AllocsPerOp()) // 1
fmt.Println("b2:", b2.AllocedBytesPerOp()) // 16
}

View File

@ -0,0 +1,17 @@
package main
import "fmt"
func main() {
hello := []byte("Hello ")
world := "world!"
helloWorld1 := append(hello, world...) // sugar
fmt.Println(string(helloWorld1))
helloWorld2 := make([]byte, len(hello)+len(world))
copy(helloWorld2, hello)
copy(helloWorld2[len(hello):], world) // sugar
fmt.Println(string(helloWorld2))
}

View File

@ -0,0 +1,39 @@
package main
import "testing"
// go test -gcflags="-d=ssa/check_bce" -bench=. bench_test.go
func process1(data string) []byte {
return []byte{
data[0], // Found IsInBounds
data[1], // Found IsInBounds
data[2], // Found IsInBounds
data[3], // Found IsInBounds
}
}
func process2(data string) []byte {
return []byte{
data[3], // Found IsInBounds
data[2],
data[1],
data[0],
}
}
var Result []byte
func BenchmarkProcess1(b *testing.B) {
data := "Hello world"
for i := 0; i < b.N; i++ {
Result = process1(data)
}
}
func BenchmarkProcess2(b *testing.B) {
data := "Hello world"
for i := 0; i < b.N; i++ {
Result = process2(data)
}
}

View File

@ -0,0 +1,12 @@
package main
import (
"fmt"
"unsafe"
)
func main() {
str := "hello"
pointer := unsafe.StringData(str[4:5])
fmt.Println(pointer, string(*pointer))
}

View File

@ -0,0 +1,32 @@
package main
import (
"testing"
"unsafe"
)
// go test -bench=. -benchmem comparison_test.go
func Convert(data []byte) string {
if len(data) == 0 {
return ""
}
return unsafe.String(unsafe.SliceData(data), len(data))
}
var Result string
func BenchmarkConvertion(b *testing.B) {
slice := []byte("Hello world!!!")
for i := 0; i < b.N; i++ {
Result = string(slice)
}
}
func BenchmarkUnsafeConvertion(b *testing.B) {
slice := []byte("Hello world!!!")
for i := 0; i < b.N; i++ {
Result = Convert(slice)
}
}

View File

@ -0,0 +1,13 @@
package main
import "unsafe"
func main() {
const str1 string = "example"
const str2 string = "example"
const str3 string = "another example"
println(unsafe.StringData(str1))
println(unsafe.StringData(str2))
println(unsafe.StringData(str3))
}

View File

@ -0,0 +1,29 @@
package main
import (
"fmt"
"unsafe"
)
/*
type SliceHeader struct {
Data unsafe.Pointer
Len int
Cap int
}
type StringHeader struct {
Data unsafe.Pointer
Len int
}
*/
func ToStringDeprecated(data []byte) string {
return *(*string)(unsafe.Pointer(&data))
}
func main() {
data := []byte{'h', 'e', 'l', 'l', 'o'}
str := ToStringDeprecated(data)
fmt.Println(str)
}

View File

@ -0,0 +1,46 @@
package main
import (
"fmt"
"testing"
)
func rangeWithoutAllocation() {
var str = "world"
for range []byte(str) { // no allocation with copy
}
}
func workWithMapsWithoutAllocation() {
key := []byte{'k', 'e', 'y'}
data := map[string]string{}
data[string(key)] = "value" // allocation with copy
_ = data[string(key)] // no allocation with copy
}
func comparisonAndConcatenation1() {
var x = []byte{1023: 'x'}
var y = []byte{1023: 'y'}
if string(x) != string(y) { // no allocation with copy
s := (" " + string(x) + string(y))[1:] // no allocation with copy
_ = s
}
}
func comparisonAndConcatenation2() {
var x = []byte{1023: 'x'}
var y = []byte{1023: 'y'}
if string(x) != string(y) { // no allocation with copy
s := string(x) + string(y) // allocation with copy
_ = s
}
}
func main() {
fmt.Println(testing.AllocsPerRun(1, comparisonAndConcatenation1)) // 1
fmt.Println(testing.AllocsPerRun(1, comparisonAndConcatenation2)) // 3
}

View File

@ -0,0 +1,63 @@
package main
// Copy-On-Write
type COWString struct {
data []byte
refs *int
}
func NewString(values ...byte) COWString {
return COWString{
data: values,
refs: new(int),
}
}
func (s *COWString) Length() int {
return len(s.data)
}
func (s *COWString) Capacity() int {
return cap(s.data)
}
func (s *COWString) ToString() string {
return string(s.data) // copying...
}
func (s *COWString) Get(idx int) byte {
// without bound checking
return s.data[idx]
}
func (s *COWString) Set(idx int, value byte) {
// without bound checking
if *s.refs > 0 {
s.data = append([]byte(nil), s.data...)
}
s.data[idx] = value
}
func (s *COWString) Copy() COWString {
(*s.refs)++
return COWString{
data: s.data,
refs: s.refs,
}
}
func (s *COWString) Append(values ...byte) {
if *s.refs > 0 {
s.data = append([]byte(nil), s.data...)
}
s.data = append(s.data, values...)
}
func main() {
str := NewString([]byte("Hello world")...)
temp := str
_ = temp
}

View File

@ -0,0 +1,11 @@
package main
import "fmt"
func main() {
// incorrect code points
data := []rune{0x0011FFFF, 0x0012FFFF}
str := string(data)
fmt.Println(str)
}

View File

@ -0,0 +1,17 @@
package main
import "fmt"
func main() {
interpreted := "\nHello\nworld!\n"
raw := `\nHello\nworld!\n`
fmt.Println(interpreted)
fmt.Println(raw)
interpretedData := []byte("\n")
rawData := []byte(`\n`)
fmt.Println("interpretedData:", interpretedData)
fmt.Println("rawData:", rawData)
}

View File

@ -0,0 +1,38 @@
package main
import (
"fmt"
"runtime"
"unsafe"
)
func printAllocs() {
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Printf("%d MB\n", m.Alloc/1024/1024)
}
func findSequence(data string) string {
for i := 0; i < len(data)-1; i++ {
if data[i] == '\n' && data[i+1] == '\t' {
return data[i+2 : i+22]
}
}
return ""
}
func main() {
data := make([]byte, 1<<30)
// let's imagine that data was read from a file
str := unsafe.String(unsafe.SliceData(data), len(data))
sequence := findSequence(str)
_ = sequence // using of sequence later
printAllocs()
runtime.GC()
printAllocs()
runtime.KeepAlive(data)
}

View File

@ -0,0 +1,22 @@
package main
import "fmt"
func CalculateFrequencies(str string) {
frequencies := [26]int{}
for _, letter := range str {
letterIdx := letter - 'a'
frequencies[letterIdx]++
}
for letterIdx, frequency := range frequencies {
if frequency != 0 {
letter := 'a' + letterIdx
fmt.Printf("%c = %d\n", letter, frequency)
}
}
}
func main() {
CalculateFrequencies("aabaacdb")
}

View File

@ -0,0 +1,8 @@
package main
import "fmt"
func main() {
fmt.Println('w' - 'a') // 119 - 97
fmt.Println('o' - 'a') // 111 - 97
}

View File

@ -0,0 +1,15 @@
package main
import (
"fmt"
"unsafe"
)
func main() {
data := []byte("Hello world")
strData := unsafe.String(unsafe.SliceData(data), len(data))
fmt.Println(strData)
data[0] = 'W'
fmt.Println(strData)
}

View File

@ -0,0 +1,26 @@
package main
import "unsafe"
func action() {}
func main() {
var str = "go"
newStr := str + "-go"
strData := unsafe.StringData(str)
newStrData := unsafe.StringData(newStr)
println("action:", action)
println("strData:", strData)
println("newStrData:", newStrData)
slice := unsafe.Slice(strData, len(str))
newSlice := unsafe.Slice(newStrData, len(newStr))
newSlice[0] = 'G'
println("newStr:", newStr)
slice[0] = 'G'
println("str:", str)
}

View File

@ -0,0 +1,27 @@
package main
import (
"testing"
)
// go test -bench=. speed_test.go
func BenchmarkByRangeBytes(b *testing.B) {
text := []byte("aaaabbbbccccddddeeeeffff")
b.ResetTimer()
for i := 0; i < b.N; i++ {
for _, _ = range text {
}
}
}
func BenchmarkByRangeStringUTF8(b *testing.B) {
text := "aaaabbbbccccddddeeeeffff"
b.ResetTimer()
for i := 0; i < b.N; i++ {
for _, _ = range text {
}
}
}

View File

@ -0,0 +1,39 @@
package main
import (
"testing"
"unicode/utf8"
)
func RunesToBytes(rs []rune) []byte {
n := 0
for _, r := range rs {
n += utf8.RuneLen(r)
}
n, bs := 0, make([]byte, n)
for _, r := range rs {
n += utf8.EncodeRune(bs[n:], r)
}
return bs
}
// go test -bench=. -benchmem perf_test.go
var Result []byte
var str string = "€€€v€wqeqwwerrerrqw12313123€€€v€€€€v€€€€v€€€€v€"
func BenchmarkConversion(b *testing.B) {
rs := []rune(str + "sdfsfs€€€v€€€€v€23423423")
for i := 0; i < b.N; i++ {
Result = RunesToBytes(rs)
}
}
func BenchmarkConversionWithStr(b *testing.B) {
rs := []rune(str + "sdfsfs€€€v€€€€v€23423423")
for i := 0; i < b.N; i++ {
Result = []byte(string(rs))
}
}

View File

@ -0,0 +1,33 @@
package main
import (
"bytes"
"unicode/utf8"
)
func Runes2Bytes(rs []rune) []byte {
n := 0
for _, r := range rs {
n += utf8.RuneLen(r)
}
n, bs := 0, make([]byte, n)
for _, r := range rs {
n += utf8.EncodeRune(bs[n:], r)
}
return bs
}
func main() {
s := "Hello world!!!"
bs := []byte(s) // string -> []byte
s = string(bs) // []byte -> string
rs := []rune(s) // string -> []rune
s = string(rs) // []rune -> string
rs = bytes.Runes(bs) // []byte -> []rune
bs = Runes2Bytes(rs) // []rune -> []byte
}

View File

@ -0,0 +1,27 @@
package main
import "testing"
// go test -bench=. comparison_test.go
func BenchmarkComparison(b *testing.B) {
bs := make([]byte, 1<<26)
s0 := string(bs)
s1 := string(bs)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = s0 == s1
}
}
func BenchmarkComparisonOptimized(b *testing.B) {
bs := make([]byte, 1<<26)
s0 := string(bs)
s1 := s0
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = s0 == s1
}
}

View File

@ -0,0 +1,45 @@
package main
import (
"fmt"
"strings"
"testing"
)
// go test -bench=. concatenation_test.go
func BenchmarkConcatenationWithSprintf(b *testing.B) {
s0 := "str1"
s1 := "str2"
s2 := "str3"
s3 := "str4"
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = fmt.Sprintf("%s%s%s%s", s0, s1, s2, s3)
}
}
func BenchmarkConcatenationWithOperatorPlus(b *testing.B) {
s0 := "str1"
s1 := "str2"
s2 := "str3"
s3 := "str4"
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = s0 + s1 + s2 + s3
}
}
func BenchmarkConcatenationWithJoin(b *testing.B) {
s0 := "str1"
s1 := "str2"
s2 := "str3"
s3 := "str4"
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = strings.Join([]string{s0, s1, s2, s3}, "")
}
}

View File

@ -0,0 +1,38 @@
package main
import (
"strings"
"testing"
)
// go test -bench=. speed_test.go
func BenchmarkSimpleConcatenation(b *testing.B) {
str := "test"
for i := 0; i < b.N; i++ {
str += "test"
}
_ = str
}
func BenchmarkConcatenationWithStringBuilder(b *testing.B) {
builder := strings.Builder{}
builder.WriteString("test")
for i := 0; i < b.N; i++ {
builder.WriteString("test")
}
_ = builder.String()
}
func BenchmarkConcatenationWithStringBuilderOptimized(b *testing.B) {
builder := strings.Builder{}
builder.Grow(4 + b.N*4)
builder.WriteString("test")
for i := 0; i < b.N; i++ {
builder.WriteString("test")
}
_ = builder.String()
}

View File

@ -0,0 +1,18 @@
package main
import "strings"
func firstWay() {
old := strings.Builder{}
// manipulating with old..
new := old
_ = new
}
func secondWay() {
old := strings.Builder{}
// manipulating with old..
new := strings.Builder{}
new.WriteString(old.String())
_ = new
}

View File

@ -0,0 +1,53 @@
package main
import "fmt"
type Builder struct {
buffer []byte
}
func NewBuilder() Builder {
return Builder{}
}
func (b *Builder) Grow(capacity int) {
if capacity < 0 {
return
}
if capacity < len(b.buffer) {
b.buffer = b.buffer[:capacity]
return
}
buffer := make([]byte, len(b.buffer), capacity)
copy(buffer, b.buffer)
b.buffer = buffer
}
func (b *Builder) Write(symbol byte) {
b.buffer = append(b.buffer, symbol)
}
func (b *Builder) At(index int) *byte {
if index < 0 || index >= len(b.buffer) {
return nil
}
return &b.buffer[index]
}
func (b *Builder) String() string {
return string(b.buffer)
}
func main() {
builder := NewBuilder()
builder.Grow(3)
builder.Write('a')
builder.Write('b')
builder.Write('c')
fmt.Println(builder.String())
}

View File

@ -0,0 +1,29 @@
package main
import "fmt"
var table = map[uint8]byte{
0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e',
5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j',
10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o',
15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't',
20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y',
25: 'z',
}
func printText(text []uint8) {
for _, codeNumber := range text {
symbol, found := table[codeNumber]
if !found {
fmt.Printf("#incorrect code symbol: %d\n", codeNumber)
return
}
fmt.Printf("%q", symbol)
}
}
func main() {
text := []uint8{7, 4, 11, 11, 14}
printText(text)
}

View File

@ -0,0 +1,10 @@
package main
import "fmt"
func main() {
str1 := "hello"
str2 := "汉hello"
fmt.Println(len(str1), len(str2))
}

View File

@ -0,0 +1,32 @@
package main
import (
"testing"
"unsafe"
)
// go test -bench=. -benchmem comparison_test.go
func Convert(str string) []byte {
if len(str) == 0 {
return nil
}
return unsafe.Slice(unsafe.StringData(str), len(str))
}
var Result []byte
func BenchmarkConvertion(b *testing.B) {
str := "Hello world!!!"
for i := 0; i < b.N; i++ {
Result = []byte(str)
}
}
func BenchmarkUnsafeConvertion(b *testing.B) {
str := "Hello world!!!"
for i := 0; i < b.N; i++ {
Result = Convert(str)
}
}

View File

@ -0,0 +1,27 @@
package main
func writeToStringSymbol() {
str := "hello"
// str[0] = 'H' -> compilation error
_ = str
}
func rewriteString() {
str := "hello"
str = "world"
// str[0] = 'H' -> compilation error
_ = str
}
func takeStringSymbolAddress() {
str := "hello"
// pointer := &str[0] -> compilation error
_ = str
}
func slicingString() {
/*
const str = "hello"
_ = str[0:10] -> compilation error
*/
}

View File

@ -0,0 +1,15 @@
package main
import "fmt"
func main() {
text := "Sr, привет 世界"
for idx, symbol := range text { // range []rune(text)
fmt.Printf("%d-%c ", idx, symbol)
}
fmt.Println()
for i := 0; i < len(text); i++ { // range []byte(text)
fmt.Printf("%d-%c ", i, text[i])
}
}

View File

@ -0,0 +1,9 @@
package main
import "fmt"
func main() {
str := "字Hello"
substr := str[:6]
fmt.Println(substr)
}

View File

@ -0,0 +1,13 @@
package main
import (
"fmt"
"strings"
)
func main() {
str := "oxo123oxo"
fmt.Println("TrimRight:", strings.TrimRight(str, "xo"))
fmt.Println("TrimSuffix:", strings.TrimSuffix(str, "xo"))
// also for strings.TrimLeft() and strings.TrimPrefix()
}

View File

@ -0,0 +1,50 @@
package main
import (
"testing"
"unique"
)
// go test -bench=. bench_test.go
var str1 = `Lorem ipsum dolor sit amet, consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt
in culpa qui officia deserunt mollit anim id est laborum`
var str2 = `Lorem ipsum dolor sit amet, consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt
in culpa qui officia deserunt mollit anim id est laborum`
var Result bool
// describe about:
// - space optimization
// - other types
// - synchronization
func BenchmarkConversion(b *testing.B) {
handle1 := unique.Make(str1 + "!!!")
handle2 := unique.Make(str2 + "!!!")
b.ResetTimer()
for i := 0; i < b.N; i++ {
Result = handle1 == handle2
}
}
func BenchmarkConversionWithStr(b *testing.B) {
sstr1 := str1 + "!!!"
sstr2 := str2 + "!!!"
b.ResetTimer()
for i := 0; i < b.N; i++ {
Result = sstr1 == sstr2
}
}