Ultimate Blinky 反射是的 , Emgo 支持 反射。 reflect 包尚未完成 , 但是已完成的部分足以实现 fmt.Pri。Go 语言在极小硬件上的运用(二)( 四 )。" />

Go 语言在极小硬件上的运用(二)( 四 )


func main() {s := "Hello, World!\r\n"mw :=--tt-darkmode-color: #999999;">Ultimate Blinky
反射是的 , Emgo 支持 反射。 reflect 包尚未完成 , 但是已完成的部分足以实现 fmt.Print 函数族了 。 来看看我们可以在小型 MCU 上做什么 。
为了减少内存使用 , 我们将使用 半主机 (semihosting) 作为标准输出 。 为了方便起见 , 我们还编写了简单的 println 函数 , 它在某种程度上类似于 fmt.Println 。
package mainimport ("debug/semihosting""reflect""strconv""stm32/hal/system""stm32/hal/system/timer/systick")var stdout semihosting.Filefunc init() {system.SetupPLL(8, 1, 48/8)systick.Setup(2e6)var err errorstdout, err = semihosting.OpenFile(":tt", semihosting.W)for err != nil {}}type stringer interface {String() string}func println(args ...interface{}) {for i, a := range args {if i > 0 {stdout.WriteString(" ")}switch v := a.(type) {case string:stdout.WriteString(v)case int:strconv.WriteInt(stdout, v, 10, 0, 0)case bool:strconv.WriteBool(stdout, v, 't', 0, 0)case stringer:stdout.WriteString(v.String())default:stdout.WriteString("%unknown")}}stdout.WriteString("\r\n")}type S struct {A intB bool}func main() {p :=i < v.NumField(); i++ {ft := v.Type().Field(i)fv := v.Field(i)println("", ft.Name(), ":", fv.Interface())}println("}")}semihosting.OpenFile 函数允许在主机端打开/创建文件 。 特殊路径 :tt 对应于主机的标准输出 。
println 函数接受任意数量的参数 , 每个参数的类型都是任意的:
func println(args ...interface{})可能是因为任何类型都实现了空接口 interface{} 。println 使用 类型开关 打印字符串 , 整数和布尔值:
switch v := a.(type) {case string:stdout.WriteString(v)case int:strconv.WriteInt(stdout, v, 10, 0, 0)case bool:strconv.WriteBool(stdout, v, 't', 0, 0)case stringer:stdout.WriteString(v.String())default:stdout.WriteString("%unknown")}此外 , 它还支持任何实现了 stringer 接口的类型 , 即任何具有 String() 方法的类型 。 在任何 case 子句中 , v 变量具有正确的类型 , 与 case 关键字后列出的类型相同 。
reflect.ValueOf(p) 函数通过允许以编程的方式分析其类型和内容的形式返回 p 。 如你所见 , 我们甚至可以使用 v.Elem() 取消引用指针 , 并打印所有结构体及其名称 。
让我们尝试编译这段代码 。 现在让我们看看如果编译时没有类型和字段名 , 会有什么结果:
$ egc -nt -nf$ arm-none-eabi-size cortexm0.elftextdatabssdechex filename160282163121655640ac cortexm0.elf闪存上只剩下 140 个可用字节 。 让我们使用启用了半主机的 OpenOCD 加载它:
$ openocd -d0 -f interface/stlink.cfg -f target/stm32f0x.cfg -c 'init; program cortexm0.elf; arm semihosting enable; reset run'Open On-Chip Debugger 0.10.0+dev-00319-g8f1f912a (2018-03-07-19:20)Licensed under GNU GPL v2For bug reports, readdebug_level: 0adapter speed: 1000 kHzadapter_nsrst_delay: 100none separateadapter speed: 950 kHztarget halted due to debug-request, current mode: ThreadxPSR: 0xc1000000 pc: 0x08002338 msp: 0x20000a20adapter speed: 4000 kHz** Programming Started **auto erase enabledtarget halted due to breakpoint, current mode: ThreadxPSR: 0x61000000 pc: 0x2000003a msp: 0x20000a20wrote 16384 bytes from file cortexm0.elf in 0.700133s (22.853 KiB/s)** Programming Finished **semihosting is enabledadapter speed: 950 kHzkind(p) = ptrkind(*p) = structtype(*p) =*p = {X. : -123X. : true}如果你实际运行此代码 , 则会注意到半主机运行缓慢 , 尤其是在逐字节写入时(缓冲很有用) 。
如你所见 , *p 没有类型名称 , 并且所有结构字段都具有相同的 X. 名称 。 让我们再次编译该程序 , 这次不带 -nt -nf 选项:
$ egc$ arm-none-eabi-size cortexm0.elftextdatabssdechex filename160522163121658040c4 cortexm0.elf现在已经包括了类型和字段名称 , 但仅在 main.go 文件中 main 包中定义了它们 。 该程序的输出如下所示:
kind(p) = ptrkind(*p) = structtype(*p) = S*p = {A : -123B : true}反射是任何易于使用的序列化库的关键部分 , 而像 JSON 这样的序列化 算法 在 物联网(IoT)时代也越来越重要 。
这些就是我完成的本文的第二部分 。 我认为有机会进行第三部分 , 更具娱乐性的部分 , 在那里我们将各种有趣的设备连接到这块板上 。 如果这块板装不下 , 我们就换一块大一点的 。
via: ziutek.github.io
作者: Micha? Derkacz 译者: gxlct008 校对: wxy
本文由 LCTT 原创编译 ,Linux中国 荣誉推出
点击“了解更多”可访问文内链接