Working on reflect lecture

This commit is contained in:
Fedor Korotkiy 2020-04-16 15:08:39 +03:00
parent bbab13a995
commit f0342454af
3 changed files with 162 additions and 0 deletions

View file

@ -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

View file

@ -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
}

View file

@ -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: "<int Value>"
- Метод `.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"