From f0342454af93158587c89cb10db1c17c926e046e Mon Sep 17 00:00:00 2001 From: Fedor Korotkiy Date: Thu, 16 Apr 2020 15:08:39 +0300 Subject: [PATCH] Working on reflect lecture --- lectures/08-reflect/format/format.go | 41 ++++++++++ lectures/08-reflect/format/format_test.go | 24 ++++++ lectures/08-reflect/lecture.slide | 97 +++++++++++++++++++++++ 3 files changed, 162 insertions(+) create mode 100644 lectures/08-reflect/format/format.go create mode 100644 lectures/08-reflect/format/format_test.go create mode 100644 lectures/08-reflect/lecture.slide diff --git a/lectures/08-reflect/format/format.go b/lectures/08-reflect/format/format.go new file mode 100644 index 0000000..a82c0b0 --- /dev/null +++ b/lectures/08-reflect/format/format.go @@ -0,0 +1,41 @@ +// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan. +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ + +// See page 332. + +// Package format provides an Any function that can format any value. +//!+ +package format + +import ( + "reflect" + "strconv" +) + +// Any formats any value as a string. +func Any(value interface{}) string { + return formatAtom(reflect.ValueOf(value)) +} + +// formatAtom formats a value without inspecting its internal structure. +func formatAtom(v reflect.Value) string { + switch v.Kind() { + case reflect.Invalid: + return "invalid" + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return strconv.FormatInt(v.Int(), 10) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return strconv.FormatUint(v.Uint(), 10) + // ...floating-point and complex cases omitted for brevity... + case reflect.Bool: + return strconv.FormatBool(v.Bool()) + case reflect.String: + return strconv.Quote(v.String()) + case reflect.Chan, reflect.Func, reflect.Ptr, reflect.Slice, reflect.Map: + return v.Type().String() + " 0x" + strconv.FormatUint(uint64(v.Pointer()), 16) + default: // reflect.Array, reflect.Struct, reflect.Interface + return v.Type().String() + " value" + } +} + +// OMIT diff --git a/lectures/08-reflect/format/format_test.go b/lectures/08-reflect/format/format_test.go new file mode 100644 index 0000000..77c0846 --- /dev/null +++ b/lectures/08-reflect/format/format_test.go @@ -0,0 +1,24 @@ +// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan. +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ + +package format_test + +import ( + "fmt" + "testing" + "time" + + "gopl.io/ch12/format" +) + +func Test(t *testing.T) { + // The pointer values are just examples, and may vary from run to run. + //!+time + var x int64 = 1 + var d time.Duration = 1 * time.Nanosecond + fmt.Println(format.Any(x)) // "1" + fmt.Println(format.Any(d)) // "1" + fmt.Println(format.Any([]int64{x})) // "[]int64 0x8202b87b0" + fmt.Println(format.Any([]time.Duration{d})) // "[]time.Duration 0x8202b87e0" + //!-time +} diff --git a/lectures/08-reflect/lecture.slide b/lectures/08-reflect/lecture.slide new file mode 100644 index 0000000..06688e7 --- /dev/null +++ b/lectures/08-reflect/lecture.slide @@ -0,0 +1,97 @@ +reflect +Лекция 7 + +Короткий Фёдор + +* Reflection + +- Механизм для чтения и изменения значений, не зная их реальный тип момент компиляции. +- Пример использования `reflect`: `fmt`, `encoding/json`. +- Эти пакеты используют `reflect` в реализации, но *не*светят* reflect в интерфейсе. + +* Why Reflection? + +Иногда нам нужно API, которое работает со значениями, которые не +объединены общим интерфейсом. + + func Sprint(x interface{}) string { + type stringer interface { + String() string + } + + switch x := x.(type) { + case stringer: + return x.String() + case string: + return x + case int: + return strconv.Itoa(x) + // ...similar cases for int16, uint32, and so on... + default: + // array, chan, func, map, pointer, slice, struct + return "???" + } + } + +* reflect.Type and reflect.Value + +- Пакет `reflect` определяет два основных типа: `reflect.Type` и `reflect.Value`. +- Единственная реализация `reflect.Type` - _type_descriptor_. + + func TypeOf(interface{}) Type + +- Пример: + + t := reflect.TypeOf(3) // a reflect.Type + fmt.Println(t.String()) // "int" + fmt.Println(t) // "int" + +- `reflect.TypeOf` всегда возвращает конкретный тип. + + var w io.Writer = os.Stdout + fmt.Println(reflect.TypeOf(w)) // "*os.File" + +- `Sprintf` формат `%T` использует `TypeOf` внутри. + + fmt.Printf("%T\n", 3) // "int" + +* reflect.Type and reflect.Value + +- `reflect.Value` хранит значение любого типа. + + v := reflect.ValueOf(3) + fmt.Println(v) // "3" + fmt.Printf("%v\n", v) // "3" + fmt.Println(v.String()) // NOTE: "" + +- Метод `.Type()` возвращает тип значения, хранящегося внутри `Value`. + + t := v.Type() // a reflect.Type + fmt.Println(t.String()) // "int" + +- Метод `.Interface()` - обратная операция к `reflect.ValueOf`. + + v := reflect.ValueOf(3) // a reflect.Value + x := v.Interface() // an interface{} + i := x.(int) // an int + fmt.Printf("%d\n", i) // "3" + +* Разница между reflect.Value и interface{} + +- Оба хранят любое значение. +- `interface{}` - хранит значение, но не даёт доступа к нему. Можно достать конкретный тип, через _type_assertion_. +- `reflect.Value` - предоставляет доступ к значению внутри, вне зависимости от типа этого значения. + +* format.Any + +.code format/format.go /func Any/,/OMIT/ + +* format.Any + + var x int64 = 1 + var d time.Duration = 1 * time.Nanosecond + fmt.Println(format.Any(x)) // "1" + fmt.Println(format.Any(d)) // "1" + fmt.Println(format.Any([]int64{x})) // "[]int64 0x8202b87b0" + fmt.Println(format.Any([]time.Duration{d})) // "[]time.Duration 0x8202b87e0" +