Исходники и презентации
This commit is contained in:
30
lessons/generics_and_reflection/cloneable_mixin/main.go
Normal file
30
lessons/generics_and_reflection/cloneable_mixin/main.go
Normal file
@ -0,0 +1,30 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type CloneableMixin[T any] struct{}
|
||||
|
||||
func (m CloneableMixin[T]) Clone() *T {
|
||||
return new(T)
|
||||
}
|
||||
|
||||
type Data1 struct {
|
||||
CloneableMixin[Data1]
|
||||
}
|
||||
|
||||
type Data2 struct {
|
||||
CloneableMixin[Data2]
|
||||
}
|
||||
|
||||
func main() {
|
||||
data1 := Data1{}
|
||||
clone1 := data1.Clone()
|
||||
fmt.Println(reflect.TypeOf(clone1)) // *main.Data1
|
||||
|
||||
data2 := Data2{}
|
||||
clone2 := data2.Clone()
|
||||
fmt.Println(reflect.TypeOf(clone2)) // *main.Data2
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Data struct {
|
||||
Value string
|
||||
}
|
||||
|
||||
func (d Data) GetValue() string {
|
||||
return d.Value
|
||||
}
|
||||
|
||||
type ValueGetter interface {
|
||||
GetValue() string
|
||||
}
|
||||
|
||||
func Print[T ValueGetter](value T) {
|
||||
fmt.Println(value.GetValue())
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Data1 struct {
|
||||
Value string
|
||||
}
|
||||
|
||||
type Data2 struct {
|
||||
Value string
|
||||
}
|
||||
|
||||
func Print1[T any](value T) {
|
||||
fmt.Println(value.Value) // compilation error
|
||||
}
|
||||
|
||||
func Print2[T Data1 | Data2](value T) {
|
||||
fmt.Println(value.Value) // compilation error
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package main
|
||||
|
||||
type Stringer interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
func ToString[T Stringer](values ...T) []string {
|
||||
result := make([]string, 0, len(values))
|
||||
for idx := range values {
|
||||
result = append(result, values[idx].String())
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
type Data struct{}
|
||||
|
||||
func (d Data) String() string {
|
||||
return "string"
|
||||
}
|
||||
|
||||
func main() {
|
||||
data := Data{}
|
||||
var idata Stringer = data
|
||||
|
||||
_ = ToString(data)
|
||||
_ = ToString(idata)
|
||||
_ = ToString(100)
|
||||
}
|
||||
45
lessons/generics_and_reflection/constraints_1/main.go
Normal file
45
lessons/generics_and_reflection/constraints_1/main.go
Normal file
@ -0,0 +1,45 @@
|
||||
package main
|
||||
|
||||
type Integer1 interface {
|
||||
int | int16 | int32 | int64
|
||||
}
|
||||
|
||||
type Integer2 interface {
|
||||
~int | ~int16 | ~int32 | ~int64
|
||||
}
|
||||
|
||||
func Process1[T1 Integer1](value T1) {
|
||||
// ..
|
||||
}
|
||||
|
||||
func Process11[T2 interface{ int | int16 | int32 | int64 }](value T2) {
|
||||
// ..
|
||||
}
|
||||
|
||||
func Process12[T2 int | int16 | int32 | int64](value T2) { // interface{} can be omitted
|
||||
// ..
|
||||
}
|
||||
|
||||
func Process2[T2 Integer2](value T2) {
|
||||
// ..
|
||||
}
|
||||
|
||||
type MyInt1 int
|
||||
type MyInt2 MyInt1
|
||||
|
||||
type MyIntAlias1 = int
|
||||
type MyIntAlias2 = MyIntAlias1
|
||||
|
||||
func main() {
|
||||
Process1(int(100))
|
||||
Process1(MyInt1(100))
|
||||
Process1(MyInt2(100))
|
||||
Process1(MyIntAlias1(100))
|
||||
Process1(MyIntAlias2(100))
|
||||
|
||||
Process2(int(100))
|
||||
Process2(MyInt1(100))
|
||||
Process2(MyInt2(100))
|
||||
Process1(MyIntAlias1(100))
|
||||
Process1(MyIntAlias2(100))
|
||||
}
|
||||
26
lessons/generics_and_reflection/constraints_2/main.go
Normal file
26
lessons/generics_and_reflection/constraints_2/main.go
Normal file
@ -0,0 +1,26 @@
|
||||
package main
|
||||
|
||||
type MyInt int
|
||||
|
||||
func (i MyInt) String() string {
|
||||
return "number"
|
||||
}
|
||||
|
||||
type Constraint interface {
|
||||
~int | ~int8 | ~int16 | ~int32 | ~int64
|
||||
String() string
|
||||
any
|
||||
|
||||
// Do()
|
||||
// interface{ Do() }
|
||||
// ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64
|
||||
}
|
||||
|
||||
func Do[T Constraint](value T) {
|
||||
// ...
|
||||
}
|
||||
|
||||
func main() {
|
||||
var value MyInt
|
||||
Do(value)
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
// generics restriction
|
||||
type _ interface {
|
||||
int | ~int // compilation error
|
||||
}
|
||||
|
||||
type _ interface {
|
||||
interface{ int } | interface{ ~int } // ok
|
||||
}
|
||||
|
||||
type _ interface {
|
||||
int | interface{ ~int } // ok
|
||||
}
|
||||
21
lessons/generics_and_reflection/constraints_union/main.go
Normal file
21
lessons/generics_and_reflection/constraints_union/main.go
Normal file
@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
type _ interface {
|
||||
[]int | comparable // compilation error
|
||||
}
|
||||
|
||||
type _ interface {
|
||||
string | error // compilation error
|
||||
}
|
||||
|
||||
type _ interface {
|
||||
string | interface{ Do() } // compilation error
|
||||
}
|
||||
|
||||
type _ interface {
|
||||
string | interface{ int } // ok
|
||||
}
|
||||
|
||||
type _ interface {
|
||||
string | interface{} // ok
|
||||
}
|
||||
24
lessons/generics_and_reflection/generic_constraint/main.go
Normal file
24
lessons/generics_and_reflection/generic_constraint/main.go
Normal file
@ -0,0 +1,24 @@
|
||||
package main
|
||||
|
||||
// constraint
|
||||
type Unsigned interface {
|
||||
uint | uint8 | uint16 | uint32 | uint64
|
||||
}
|
||||
|
||||
type Slice[T any] []T
|
||||
|
||||
type SliceConstaint[E Unsigned] interface {
|
||||
Slice[E]
|
||||
}
|
||||
|
||||
func Do[E Unsigned, T SliceConstaint[E]](values T) {
|
||||
// ...
|
||||
}
|
||||
|
||||
func main() {
|
||||
var slice1 Slice[uint8]
|
||||
var slice2 Slice[uint16]
|
||||
|
||||
Do(slice1)
|
||||
Do(slice2)
|
||||
}
|
||||
17
lessons/generics_and_reflection/generic_decorator/main.go
Normal file
17
lessons/generics_and_reflection/generic_decorator/main.go
Normal file
@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func Decorator[T any](fn func(T), decorator func(T) T) func(T) {
|
||||
return func(input T) {
|
||||
fn(decorator(input))
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
print := func(value int) { fmt.Println(value) }
|
||||
double := func(value int) int { return value * value }
|
||||
|
||||
decorated := Decorator(print, double)
|
||||
decorated(10)
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
// constraint
|
||||
type Signed interface {
|
||||
int | int8 | int16 | int32 | int64
|
||||
}
|
||||
|
||||
type Counter struct {
|
||||
value int64
|
||||
}
|
||||
|
||||
func Add[T Signed](c *Counter, value T) {
|
||||
c.value += int64(value)
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
// constraint
|
||||
type Signed interface {
|
||||
int | int8 | int16 | int32 | int64
|
||||
}
|
||||
|
||||
type Counter struct {
|
||||
value int64
|
||||
}
|
||||
|
||||
func (c *Counter) Add[T Signed](value T) { // compilation erro
|
||||
c.value += int64(value)
|
||||
}
|
||||
15
lessons/generics_and_reflection/generic_method_set/main.go
Normal file
15
lessons/generics_and_reflection/generic_method_set/main.go
Normal file
@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
type S struct{}
|
||||
|
||||
func (S) Bar() {}
|
||||
|
||||
type C interface {
|
||||
S
|
||||
Foo()
|
||||
}
|
||||
|
||||
func foobar[T C](value T) {
|
||||
value.Foo()
|
||||
value.Bar() // compilation error
|
||||
}
|
||||
37
lessons/generics_and_reflection/generic_set/main.go
Normal file
37
lessons/generics_and_reflection/generic_set/main.go
Normal file
@ -0,0 +1,37 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Set[K comparable] struct {
|
||||
data map[K]struct{}
|
||||
}
|
||||
|
||||
func NewSet[K comparable]() Set[K] {
|
||||
return Set[K]{
|
||||
data: make(map[K]struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Set[K]) Insert(key K) {
|
||||
s.data[key] = struct{}{}
|
||||
}
|
||||
|
||||
func (s *Set[K]) Erase(key K) {
|
||||
delete(s.data, key)
|
||||
}
|
||||
|
||||
func (s *Set[K]) Contains(key K) bool {
|
||||
_, found := s.data[key]
|
||||
return found
|
||||
}
|
||||
|
||||
// skipping like with function
|
||||
func (s *Set[_]) Print() {
|
||||
fmt.Println(s.data)
|
||||
}
|
||||
|
||||
func main() {
|
||||
set := NewSet[string]()
|
||||
set.Insert("key")
|
||||
set.Erase("key")
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
func Process[T any](data ...T) {
|
||||
// processing
|
||||
}
|
||||
|
||||
func main() {
|
||||
Process(2, 5, 10)
|
||||
Process("one", "two")
|
||||
Process(0.3)
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func process1[T []byte | [2]byte | string](value T) {
|
||||
_ = value[0]
|
||||
}
|
||||
|
||||
func process2[T map[int]string](value T) {
|
||||
_ = value[0]
|
||||
}
|
||||
|
||||
func process3[T map[int]string|[]byte](value T) {
|
||||
_ = value[0]
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
package main
|
||||
|
||||
func process[T ~string | ~[]byte](value T, index int) {
|
||||
_ = value[index]
|
||||
value[index] = byte('a') // error
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
func process1[T int]() {
|
||||
const value T = 5 // compilation error
|
||||
}
|
||||
|
||||
func process2[T int]() {
|
||||
var value T = 5 // ok
|
||||
_ = value
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func process1[T int32 | int64](value *T) {
|
||||
*value = *value + 1 // ok
|
||||
}
|
||||
|
||||
func process2[T *int32 | *int64](value T) {
|
||||
*value = *value + 1 // compilation error
|
||||
}
|
||||
|
||||
func process3[T *Int, Int int32 | int64](value T) {
|
||||
*value = *value + 1 // ok
|
||||
}
|
||||
25
lessons/generics_and_reflection/generics_with_unsafe/main.go
Normal file
25
lessons/generics_and_reflection/generics_with_unsafe/main.go
Normal file
@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func store[T any](pointer unsafe.Pointer, value T) {
|
||||
*(*T)(pointer) = value
|
||||
}
|
||||
|
||||
func load[T any](pointer unsafe.Pointer) T {
|
||||
return *(*T)(pointer)
|
||||
}
|
||||
|
||||
func main() {
|
||||
var pointer1 unsafe.Pointer // not initialized
|
||||
var pointer2 unsafe.Pointer // not initialized
|
||||
|
||||
store[int16](pointer1, 100)
|
||||
store[int32](pointer2, 200)
|
||||
|
||||
value1 := load[int16](pointer1)
|
||||
value2 := load[int32](pointer2)
|
||||
|
||||
_ = value1
|
||||
_ = value2
|
||||
}
|
||||
26
lessons/generics_and_reflection/map_keys/main.go
Normal file
26
lessons/generics_and_reflection/map_keys/main.go
Normal file
@ -0,0 +1,26 @@
|
||||
package main
|
||||
|
||||
func GetKeys(data map[string]int) []string {
|
||||
keys := make([]string, 0, len(data))
|
||||
for key := range data {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
|
||||
return keys
|
||||
}
|
||||
|
||||
// any -> alias for interface{}
|
||||
// comparable -> constraint for != and ==
|
||||
func GetKeysGeneric[K comparable, V any](data map[K]V) []K {
|
||||
keys := make([]K, 0, len(data))
|
||||
for key := range data {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
|
||||
return keys
|
||||
}
|
||||
|
||||
func main() {
|
||||
GetKeys(map[string]int{})
|
||||
GetKeysGeneric[int, int](map[int]int{})
|
||||
}
|
||||
25
lessons/generics_and_reflection/max/main.go
Normal file
25
lessons/generics_and_reflection/max/main.go
Normal file
@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
func MaxInt(lhs, rhs int) int {
|
||||
if lhs >= rhs {
|
||||
return lhs
|
||||
} else {
|
||||
return rhs
|
||||
}
|
||||
}
|
||||
|
||||
func MaxUInt(lhs, rhs uint) uint {
|
||||
if lhs >= rhs {
|
||||
return lhs
|
||||
} else {
|
||||
return rhs
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
var lhs1, rhs1 int = 10, 20
|
||||
_ = MaxInt(lhs1, rhs1)
|
||||
|
||||
var lhs2, rhs2 uint = 10, 20
|
||||
_ = MaxUInt(lhs2, rhs2)
|
||||
}
|
||||
32
lessons/generics_and_reflection/max_generic/main.go
Normal file
32
lessons/generics_and_reflection/max_generic/main.go
Normal file
@ -0,0 +1,32 @@
|
||||
package main
|
||||
|
||||
// constraint
|
||||
type Signed interface {
|
||||
int | int8 | int16 | int32 | int64
|
||||
}
|
||||
|
||||
// constraint
|
||||
type Unsigned interface {
|
||||
uint | uint8 | uint16 | uint32 | uint64
|
||||
}
|
||||
|
||||
// constraint
|
||||
type Integer interface {
|
||||
Signed | Unsigned
|
||||
}
|
||||
|
||||
func Max[T Integer](lhs, rhs T) T {
|
||||
if lhs >= rhs {
|
||||
return lhs
|
||||
} else {
|
||||
return rhs
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
var lhs1, rhs1 int = 10, 20
|
||||
_ = Max[int](lhs1, rhs1)
|
||||
|
||||
var lhs2, rhs2 uint = 10, 20
|
||||
_ = Max[uint](lhs2, rhs2)
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
type Data struct{}
|
||||
|
||||
func (d Data) Do1() {}
|
||||
|
||||
type Constraint interface {
|
||||
Data
|
||||
Do2()
|
||||
}
|
||||
|
||||
// generics restriction
|
||||
func GenericDo[T Constraint](value T) {
|
||||
value.Do1() // compilation error
|
||||
value.Do2() // ok
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
type T[T1 any, T2 any] struct{}
|
||||
|
||||
type TypeAlias1 = T[string, int]
|
||||
type TypeAlias2[T1 any] = T[T1, int]
|
||||
|
||||
type TypeDefinition1 T[string, int]
|
||||
type TypeDefinition2[T1 any] T[T1, int]
|
||||
56
lessons/generics_and_reflection/private_fields_1/main.go
Normal file
56
lessons/generics_and_reflection/private_fields_1/main.go
Normal file
@ -0,0 +1,56 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type Data struct {
|
||||
age int8
|
||||
address string
|
||||
}
|
||||
|
||||
func getFieldOffset(instance interface{}, fieldName string) (uintptr, error) {
|
||||
instanceValue := reflect.ValueOf(instance)
|
||||
if instanceValue.Kind() != reflect.Ptr {
|
||||
return 0, fmt.Errorf("the first parameter must be a pointer to a struct")
|
||||
}
|
||||
|
||||
instanceType := instanceValue.Type().Elem()
|
||||
field, found := instanceType.FieldByName(fieldName)
|
||||
if !found {
|
||||
return 0, fmt.Errorf("field '%s' not found in the struct", fieldName)
|
||||
}
|
||||
|
||||
return field.Offset, nil
|
||||
}
|
||||
|
||||
func AssignPrivateField[T any, V any](src *T, field string, value V) error {
|
||||
offset, err := getFieldOffset(src, field)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get offset: %w", err)
|
||||
}
|
||||
|
||||
fieldPtr := (*V)(unsafe.Add(unsafe.Pointer(src), offset))
|
||||
*fieldPtr = value
|
||||
return nil
|
||||
}
|
||||
|
||||
func ReadPrivateField[T any, V any](src *T, field string) (V, error) {
|
||||
var output V
|
||||
|
||||
offset, err := getFieldOffset(src, field)
|
||||
if err != nil {
|
||||
return output, fmt.Errorf("get offset: %w", err)
|
||||
}
|
||||
|
||||
output = *(*V)(unsafe.Add(unsafe.Pointer(src), offset))
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
data := &Data{}
|
||||
_ = AssignPrivateField(data, "address", "Moscow")
|
||||
fmt.Println(data)
|
||||
}
|
||||
24
lessons/generics_and_reflection/private_fields_2/main.go
Normal file
24
lessons/generics_and_reflection/private_fields_2/main.go
Normal file
@ -0,0 +1,24 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type Data struct {
|
||||
value string
|
||||
}
|
||||
|
||||
func main() {
|
||||
data := Data{
|
||||
value: "it's a secret",
|
||||
}
|
||||
|
||||
field := reflect.ValueOf(&data).Elem().FieldByName("value")
|
||||
pointer := unsafe.Pointer(field.UnsafeAddr())
|
||||
strPtr := (*string)(pointer)
|
||||
|
||||
*strPtr = "it's not a secret"
|
||||
fmt.Println(data.value)
|
||||
}
|
||||
15
lessons/generics_and_reflection/reflect_can_set/main.go
Normal file
15
lessons/generics_and_reflection/reflect_can_set/main.go
Normal file
@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var value float64 = 3.14
|
||||
v := reflect.ValueOf(value) // copy of value
|
||||
//v.SetFloat(2.7)
|
||||
//v.Addr()
|
||||
|
||||
fmt.Println("settability of v:", v.CanSet())
|
||||
}
|
||||
32
lessons/generics_and_reflection/reflect_channel/main.go
Normal file
32
lessons/generics_and_reflection/reflect_channel/main.go
Normal file
@ -0,0 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ch := make(chan string, 2)
|
||||
|
||||
vCh := reflect.ValueOf(ch)
|
||||
vCh.Send(reflect.ValueOf("Go"))
|
||||
|
||||
succeeded := vCh.TrySend(reflect.ValueOf("C++"))
|
||||
fmt.Println("C++", succeeded)
|
||||
|
||||
succeeded = vCh.TrySend(reflect.ValueOf("Java"))
|
||||
fmt.Println("Java", succeeded)
|
||||
|
||||
fmt.Println(vCh.Len(), vCh.Cap())
|
||||
|
||||
value, ok := vCh.Recv()
|
||||
fmt.Println(value, ok)
|
||||
|
||||
value, ok = vCh.TryRecv()
|
||||
fmt.Println(value, ok)
|
||||
|
||||
value, ok = vCh.TryRecv()
|
||||
fmt.Println(value, ok)
|
||||
|
||||
vCh.Close()
|
||||
}
|
||||
16
lessons/generics_and_reflection/reflect_comparable/main.go
Normal file
16
lessons/generics_and_reflection/reflect_comparable/main.go
Normal file
@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var str string
|
||||
var number int
|
||||
var slice []int
|
||||
|
||||
fmt.Println("str:", reflect.ValueOf(str).Comparable())
|
||||
fmt.Println("number:", reflect.ValueOf(number).Comparable())
|
||||
fmt.Println("slice:", reflect.ValueOf(slice).Comparable())
|
||||
}
|
||||
20
lessons/generics_and_reflection/reflect_convertible/main.go
Normal file
20
lessons/generics_and_reflection/reflect_convertible/main.go
Normal file
@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func main() {
|
||||
vData := reflect.ValueOf([]int{1, 2, 3})
|
||||
|
||||
tData := vData.Type()
|
||||
t1 := reflect.TypeOf(&[3]int{})
|
||||
t2 := reflect.TypeOf([3]int{})
|
||||
|
||||
fmt.Println(tData.ConvertibleTo(t1))
|
||||
fmt.Println(tData.ConvertibleTo(t2))
|
||||
|
||||
fmt.Println(vData.CanConvert(t1))
|
||||
fmt.Println(vData.CanConvert(t2))
|
||||
}
|
||||
22
lessons/generics_and_reflection/reflect_creation/main.go
Normal file
22
lessons/generics_and_reflection/reflect_creation/main.go
Normal file
@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func main() {
|
||||
dataStruct := reflect.StructOf([]reflect.StructField{
|
||||
{Name: "Age", Type: reflect.TypeOf("abc")},
|
||||
})
|
||||
|
||||
fmt.Println("dataStruct:", dataStruct)
|
||||
|
||||
dataArray := reflect.ArrayOf(5, reflect.TypeOf(123))
|
||||
|
||||
fmt.Println("dataArray:", dataArray)
|
||||
|
||||
dataPointer := reflect.PointerTo(dataArray)
|
||||
|
||||
fmt.Println("dataPointer:", dataPointer)
|
||||
}
|
||||
21
lessons/generics_and_reflection/reflect_dynamic_type/main.go
Normal file
21
lessons/generics_and_reflection/reflect_dynamic_type/main.go
Normal file
@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var z = 100
|
||||
var y = &z
|
||||
var x interface{} = y
|
||||
|
||||
v := reflect.ValueOf(&x)
|
||||
vx := v.Elem()
|
||||
vy := vx.Elem()
|
||||
vz := vy.Elem()
|
||||
|
||||
fmt.Println(vx, vy, vz)
|
||||
vz.Set(reflect.ValueOf(200))
|
||||
fmt.Println(vx, vy, vz)
|
||||
}
|
||||
25
lessons/generics_and_reflection/reflect_elem/main.go
Normal file
25
lessons/generics_and_reflection/reflect_elem/main.go
Normal file
@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var value float64 = 3.14
|
||||
v := reflect.ValueOf(&value) // copy of value
|
||||
|
||||
fmt.Println("type of v:", v.Type())
|
||||
fmt.Println("settability of v:", v.CanSet())
|
||||
fmt.Println("addresability of v:", v.CanAddr())
|
||||
|
||||
fmt.Println("type of v.Elem():", v.Elem().Type()) // dereference
|
||||
fmt.Println("settability of v.Elem():", v.Elem().CanSet()) // dereference
|
||||
fmt.Println("addresability of v.Elem():", v.Elem().CanAddr()) // dereference
|
||||
|
||||
v.Elem().SetFloat(2.7)
|
||||
|
||||
fmt.Println(v.Elem().Addr())
|
||||
fmt.Println("value:", value)
|
||||
fmt.Println("address:", &value)
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type Vector struct {
|
||||
X int
|
||||
Y int
|
||||
}
|
||||
|
||||
func (v Vector) Add(factor int) int {
|
||||
return (v.X + v.Y) * factor
|
||||
}
|
||||
|
||||
func main() {
|
||||
vector := Vector{X: 5, Y: 15}
|
||||
vVector := reflect.ValueOf(vector)
|
||||
|
||||
vAdd := vVector.MethodByName("Add")
|
||||
vResults := vAdd.Call([]reflect.Value{reflect.ValueOf(2)})
|
||||
|
||||
fmt.Println(vResults[0].Int())
|
||||
|
||||
negative := func(x int) int {
|
||||
return -x
|
||||
}
|
||||
|
||||
vNegative := reflect.ValueOf(negative)
|
||||
vResults = vNegative.Call([]reflect.Value{reflect.ValueOf(100)})
|
||||
fmt.Println(vResults[0].Int())
|
||||
}
|
||||
32
lessons/generics_and_reflection/reflect_generic/main.go
Normal file
32
lessons/generics_and_reflection/reflect_generic/main.go
Normal file
@ -0,0 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func InvertSlice(args []reflect.Value) []reflect.Value {
|
||||
inSlice, length := args[0], args[0].Len()
|
||||
outSlice := reflect.MakeSlice(inSlice.Type(), 0, length)
|
||||
for idx := length - 1; idx >= 0; idx-- {
|
||||
element := inSlice.Index(idx)
|
||||
outSlice = reflect.Append(outSlice, element)
|
||||
}
|
||||
|
||||
return []reflect.Value{outSlice}
|
||||
}
|
||||
|
||||
func Bind(value interface{}, fn func([]reflect.Value) []reflect.Value) {
|
||||
invert := reflect.ValueOf(value).Elem()
|
||||
invert.Set(reflect.MakeFunc(invert.Type(), fn))
|
||||
}
|
||||
|
||||
func main() {
|
||||
var invertInts func([]int) []int
|
||||
Bind(&invertInts, InvertSlice)
|
||||
fmt.Println(invertInts([]int{2, 3, 5}))
|
||||
|
||||
var invertStrs func([]string) []string
|
||||
Bind(&invertStrs, InvertSlice)
|
||||
fmt.Println(invertStrs([]string{"C++", "Go"}))
|
||||
}
|
||||
20
lessons/generics_and_reflection/reflect_implements/main.go
Normal file
20
lessons/generics_and_reflection/reflect_implements/main.go
Normal file
@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
Method()
|
||||
}
|
||||
|
||||
type Data struct{}
|
||||
|
||||
func (c Data) Method() {}
|
||||
|
||||
func main() {
|
||||
dataType := reflect.TypeOf(Data{})
|
||||
interfaceType := reflect.TypeOf((*Interface)(nil)).Elem()
|
||||
fmt.Println("implements:", dataType.Implements(interfaceType))
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var value float32 = 3.14
|
||||
v := reflect.ValueOf(value)
|
||||
iValue := v.Interface()
|
||||
fmt.Println(iValue.(float32))
|
||||
}
|
||||
13
lessons/generics_and_reflection/reflect_leak/main.go
Normal file
13
lessons/generics_and_reflection/reflect_leak/main.go
Normal file
@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func main() {
|
||||
pointer1 := reflect.ValueOf(new(int)).Pointer() // unsafe
|
||||
pointer2 := reflect.ValueOf(new(int)).UnsafePointer() // safe
|
||||
|
||||
_ = pointer1
|
||||
_ = pointer2
|
||||
}
|
||||
18
lessons/generics_and_reflection/reflect_map/main.go
Normal file
18
lessons/generics_and_reflection/reflect_map/main.go
Normal file
@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := map[string]int{"data1": 100, "data2": 200}
|
||||
|
||||
vData := reflect.ValueOf(data)
|
||||
vData.SetMapIndex(reflect.ValueOf("data1"), reflect.ValueOf(1000))
|
||||
vData.SetMapIndex(reflect.ValueOf("data2"), reflect.ValueOf(2000))
|
||||
|
||||
for it := vData.MapRange(); it.Next(); {
|
||||
fmt.Println(it.Key(), it.Value())
|
||||
}
|
||||
}
|
||||
17
lessons/generics_and_reflection/reflect_nothing/main.go
Normal file
17
lessons/generics_and_reflection/reflect_nothing/main.go
Normal file
@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var value1 reflect.Value
|
||||
fmt.Println(value1)
|
||||
|
||||
value2 := reflect.ValueOf((*int)(nil)).Elem()
|
||||
fmt.Println(value2)
|
||||
|
||||
value3 := reflect.ValueOf([]interface{}{nil}).Index(0)
|
||||
fmt.Println(value3)
|
||||
}
|
||||
24
lessons/generics_and_reflection/reflect_select/main.go
Normal file
24
lessons/generics_and_reflection/reflect_select/main.go
Normal file
@ -0,0 +1,24 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ch := make(chan int, 1)
|
||||
|
||||
vch := reflect.ValueOf(ch)
|
||||
succeed := vch.TrySend(reflect.ValueOf(100))
|
||||
fmt.Println(succeed, vch.Len(), vch.Cap())
|
||||
|
||||
branches := []reflect.SelectCase{
|
||||
{Dir: reflect.SelectDefault},
|
||||
{Dir: reflect.SelectRecv, Chan: vch},
|
||||
}
|
||||
|
||||
index, vRecv, recvOk := reflect.Select(branches)
|
||||
fmt.Println(index, vRecv, recvOk)
|
||||
|
||||
vch.Close()
|
||||
}
|
||||
30
lessons/generics_and_reflection/reflect_struct/main.go
Normal file
30
lessons/generics_and_reflection/reflect_struct/main.go
Normal file
@ -0,0 +1,30 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type Data struct {
|
||||
Count int
|
||||
Title string
|
||||
}
|
||||
|
||||
func (d Data) Do() {}
|
||||
|
||||
func main() {
|
||||
data := Data{}
|
||||
|
||||
tData := reflect.TypeOf(data)
|
||||
fmt.Println("Kind:", tData.Kind())
|
||||
fmt.Println("PkgPath:", tData.PkgPath())
|
||||
|
||||
fmt.Println("NumField:", tData.NumField())
|
||||
fmt.Println("Field(0):", tData.Field(0).Name)
|
||||
fmt.Println("Field(1):", tData.Field(1).Name)
|
||||
|
||||
fmt.Println("NumMethod:", tData.NumMethod())
|
||||
fmt.Println("Method(0):", tData.Method(0).Name)
|
||||
fmt.Println("Method(0).NumIn:", tData.Method(0).Type.NumIn())
|
||||
fmt.Println("Method(0).NumOut:", tData.Method(0).Type.NumOut())
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type Data struct {
|
||||
X int `json:"x" xml:"name"`
|
||||
Y bool `json:"y,omitempty"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
t := reflect.TypeOf(Data{})
|
||||
tXTag := t.Field(0).Tag
|
||||
tYTag := t.Field(1).Tag
|
||||
|
||||
fmt.Println(reflect.TypeOf(tXTag), reflect.TypeOf(tYTag))
|
||||
|
||||
value, present := tXTag.Lookup("json")
|
||||
fmt.Println(value, present)
|
||||
value, present = tYTag.Lookup("json")
|
||||
fmt.Println(value, present)
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var value float64 = 3.4
|
||||
|
||||
// неявное преобразование в пустой интерфейс
|
||||
fmt.Println("type:", reflect.TypeOf(value)) // func TypeOf(i any) reflect.Type
|
||||
fmt.Println("type:", reflect.ValueOf(value)) // func ValueOf(i any) reflect.Value
|
||||
|
||||
equal := reflect.ValueOf(value).Type() == reflect.TypeOf(value)
|
||||
fmt.Println("equal:", equal)
|
||||
|
||||
kind := reflect.ValueOf(value).Kind()
|
||||
fmt.Println("equal reflect.Float64:", reflect.Float64 == kind)
|
||||
|
||||
value = reflect.ValueOf(value).Float()
|
||||
_ = value
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var x uint8 = 10
|
||||
v := reflect.ValueOf(x)
|
||||
|
||||
fmt.Println("type:", v.Type())
|
||||
fmt.Println("kind:", v.Kind())
|
||||
|
||||
x = uint8(v.Uint()) // uint64
|
||||
_ = x
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type Data struct {
|
||||
Value1 int
|
||||
value2 int
|
||||
}
|
||||
|
||||
func main() {
|
||||
data := Data{Value1: 100, value2: 200}
|
||||
v := reflect.ValueOf(&data).Elem()
|
||||
t := v.Type()
|
||||
|
||||
for idx := 0; idx < v.NumField(); idx++ {
|
||||
field := v.Field(idx)
|
||||
fmt.Println(t.Field(idx).Name, field.CanSet(), field.CanAddr())
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type IntAlias = int
|
||||
type IntDefinition int
|
||||
|
||||
func main() {
|
||||
var value1 IntAlias = 7
|
||||
v1 := reflect.ValueOf(value1)
|
||||
|
||||
fmt.Println("alias type:", v1.Type())
|
||||
fmt.Println("alias kind:", v1.Kind())
|
||||
|
||||
var value2 IntDefinition = 7
|
||||
v2 := reflect.ValueOf(value2)
|
||||
|
||||
fmt.Println("definition type:", v2.Type())
|
||||
fmt.Println("definition kind:", v2.Kind())
|
||||
}
|
||||
23
lessons/generics_and_reflection/type_aliases/main.go
Normal file
23
lessons/generics_and_reflection/type_aliases/main.go
Normal file
@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
type NewType[T any] T // may not be used as the source types
|
||||
|
||||
type Set1[K comparable] map[K]struct{}
|
||||
type Set2[K comparable] = map[K]struct{} // generic type aliases are not supported
|
||||
|
||||
type SetBool1 Set1[bool]
|
||||
type SetBool2 = Set1[bool]
|
||||
|
||||
type Comparable1 comparable
|
||||
type Comparable2 = comparable
|
||||
|
||||
type Constraint1 interface{ int | uint }
|
||||
type Constraint2 = interface{ int | uint }
|
||||
|
||||
func main() {
|
||||
setStr := Set1[string]{}
|
||||
_ = setStr
|
||||
|
||||
setBool := SetBool1{}
|
||||
_ = setBool
|
||||
}
|
||||
41
lessons/generics_and_reflection/type_assertions/main.go
Normal file
41
lessons/generics_and_reflection/type_assertions/main.go
Normal file
@ -0,0 +1,41 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func IsInt1[T any](x T) bool {
|
||||
_, ok := any(x).(int)
|
||||
return ok
|
||||
}
|
||||
|
||||
func Is1[T int | string](x T) {
|
||||
switch any(x).(type) {
|
||||
//case T:
|
||||
// fmt.Println("int")
|
||||
case int:
|
||||
fmt.Println("int")
|
||||
case string:
|
||||
fmt.Println("string")
|
||||
}
|
||||
}
|
||||
|
||||
func IsInt2[T any](x T) bool {
|
||||
_, ok := x.(int) // cannot use type assertion on type parameter
|
||||
return ok
|
||||
}
|
||||
|
||||
func Is2[T int | string](x T) {
|
||||
switch x.(type) { // cannot use type switch on type parameter
|
||||
case int:
|
||||
fmt.Println("int")
|
||||
case string:
|
||||
fmt.Println("string")
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("IsInt(100):", IsInt1(100))
|
||||
fmt.Println(`IsInt("100"):`, IsInt1("100"))
|
||||
|
||||
Is1("100")
|
||||
Is1(100)
|
||||
}
|
||||
38
lessons/generics_and_reflection/type_inference/main.go
Normal file
38
lessons/generics_and_reflection/type_inference/main.go
Normal file
@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func Create[T any]() *T {
|
||||
return new(T)
|
||||
}
|
||||
|
||||
func Print[T any](value T) {
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
func MultiplePrint[T1 any, T2 any](lhs T1, rhs T2) {
|
||||
fmt.Println(lhs, rhs)
|
||||
}
|
||||
|
||||
type Data[T any] struct {
|
||||
Value T
|
||||
}
|
||||
|
||||
func main() {
|
||||
// without infence
|
||||
value1 := Create()
|
||||
_ = value1
|
||||
var value2 *int = Create()
|
||||
_ = value2
|
||||
|
||||
// with infence
|
||||
Print(100)
|
||||
Print("hello")
|
||||
MultiplePrint(100, "hello")
|
||||
|
||||
// without infence
|
||||
data1 := Data{}
|
||||
_ = data1
|
||||
data2 := Data{Value: 100}
|
||||
_ = data2
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
type Base1[Derived any] struct {
|
||||
Derived // compilation error
|
||||
}
|
||||
|
||||
type Base2[Derived any] struct {
|
||||
d Derived // ok
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package main
|
||||
|
||||
func Process1[T any, K comparable, V any](key K, value V) {
|
||||
// implementation
|
||||
}
|
||||
|
||||
func Process2[K comparable, V any, T any](key K, value V) {
|
||||
// implementation
|
||||
}
|
||||
|
||||
func Process3[T any, _ comparable, _ any](value T) {
|
||||
// implementation
|
||||
}
|
||||
|
||||
func Process4[T1, T2 any, _ comparable](value1 T1, value2 T2) {
|
||||
// implementation
|
||||
}
|
||||
|
||||
func Process5[_ any, _ any]() {
|
||||
// implementation
|
||||
}
|
||||
|
||||
func main() {
|
||||
Process1[int]("key", []int{100}) // partial argument list only with prefix
|
||||
Process2[int]("key", []int{100}) // compilation error with suffix
|
||||
|
||||
Process3[int, string, float32](100)
|
||||
Process2[int, _, float32](100) // compilation error
|
||||
}
|
||||
23
lessons/generics_and_reflection/universal_fabric/main.go
Normal file
23
lessons/generics_and_reflection/universal_fabric/main.go
Normal file
@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
type Creator[T any] func() T
|
||||
|
||||
func NewInstance[T any](creator Creator[T]) T {
|
||||
return creator()
|
||||
}
|
||||
|
||||
type (
|
||||
Book struct{}
|
||||
Game struct{}
|
||||
)
|
||||
|
||||
func main() {
|
||||
bookCreator := func() Book { return Book{} }
|
||||
gameCreator := func() Game { return Game{} }
|
||||
|
||||
book := NewInstance(bookCreator)
|
||||
_ = book
|
||||
|
||||
game := NewInstance(gameCreator)
|
||||
_ = game
|
||||
}
|
||||
14
lessons/generics_and_reflection/unnamed_types/main.go
Normal file
14
lessons/generics_and_reflection/unnamed_types/main.go
Normal file
@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
func process1[T1 int, T2 *T1]() {
|
||||
}
|
||||
|
||||
func process2[T1 *T2, T2 int]() {
|
||||
}
|
||||
|
||||
func process3[T1 *T1]() {
|
||||
}
|
||||
|
||||
func process4[T ~string | ~int, A ~[2]T, B ~chan T]() {
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user