Working on reflect lecture
This commit is contained in:
parent
bbab13a995
commit
f0342454af
3 changed files with 162 additions and 0 deletions
41
lectures/08-reflect/format/format.go
Normal file
41
lectures/08-reflect/format/format.go
Normal 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
|
24
lectures/08-reflect/format/format_test.go
Normal file
24
lectures/08-reflect/format/format_test.go
Normal 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
|
||||||
|
}
|
97
lectures/08-reflect/lecture.slide
Normal file
97
lectures/08-reflect/lecture.slide
Normal 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"
|
||||||
|
|
Loading…
Reference in a new issue