GO语言入门指南第三篇 | 青训营

82 阅读3分钟

引言

开始记录GO语言圣经第一章第四小节GIF动画的学习。

GIF 动画

在Go语言标准库中,image这个package可以用来生成一系列的bit-mapped图,然后将这些图片编码为一个GIF动画。需要注意的是,要看这个程序的结果,需要将标准输出重定向到一个GIF图像文件(使用 ./lissajous > output.gif 命令)。 具体代码如下 package main

import ( "image" "image/color" "image/gif" "io" "math" "math/rand" "os" "time" )

var palette = []color.Color{color.White, color.Black}

const ( whiteIndex = 0 // first color in palette blackIndex = 1 // next color in palette )

func main() { // The sequence of images is deterministic unless we seed // the pseudo-random number generator using the current time. // Thanks to Randall McPherson for pointing out the omission. rand.Seed(time.Now().UTC().UnixNano()) lissajous(os.Stdout) }

func lissajous(out io.Writer) { const ( cycles = 5 // number of complete x oscillator revolutions res = 0.001 // angular resolution size = 100 // image canvas covers [-size..+size] nframes = 64 // number of animation frames delay = 8 // delay between frames in 10ms units )

freq := rand.Float64() * 3.0 // relative frequency of y oscillator
anim := gif.GIF{LoopCount: nframes}
phase := 0.0 // phase difference
for i := 0; i < nframes; i++ {
    rect := image.Rect(0, 0, 2*size+1, 2*size+1)
    img := image.NewPaletted(rect, palette)
    for t := 0.0; t < cycles*2*math.Pi; t += res {
        x := math.Sin(t)
        y := math.Sin(t*freq + phase)
        img.SetColorIndex(size+int(x*size+0.5), size+int(y*size+0.5),
            blackIndex)
    }
    phase += 0.1
    anim.Delay = append(anim.Delay, delay)
    anim.Image = append(anim.Image, img)
}
gif.EncodeAll(out, &anim) // NOTE: ignoring encoding errors

}

import

当我们import了一个包路径包含有多个单词的package时,比如image/color(这个package包含了image和color两个单词),一般情况下我们只需要用最后那个单词表示这个包就可以。在这个程序中,当我们写color.White时,这个变量指向的是image/color包里的变量,与此同理,gif.GIF是属于image/gif包里的变量。

const声明

这个程序里的常量声明给出了一系列的常量值。在GO语言中,常量是指在程序编译后运行时始终都不会变化的值,比如圈数、帧数、延迟值。python语言则没有使用语法强制定义常量,也就是说python定义中的常量本质上就是变量。在GO中,常量声明和变量声明一般都会出现在包级别,所以这些常量在整个包中都是可以共享的,或者你也可以把常量声明定义在函数体内部,那么这种常量就只能在函数体内用。目前常量声明的值必须是一个数字值、字符串或者一个固定的boolean值。

复合声明

color.Color{...}和gif.GIF{...}这两个表达式就是我们说的复合声明。这里的前者生成的是一个切片,后者生成的是一个结构体。结构体是一组值或者叫字段的集合,不同的类型集合在一个结构体可以让我们以一个统一的单元进行处理。anim是一个gif.GIF类型的struct变量。这种写法会生成一个struct变量,并且其内部变量LoopCount字段会被设置为nframes;而其它的字段会被设置为各自类型对应的零值。struct内部的变量可以以一个点(.)来进行访问,就像在最后两个赋值语句中显式地更新了anim这个struct的Delay和Image字段。

lissajous函数

lissajous函数内部有两层嵌套的for循环。外层循环会循环64次,每一次都会生成一个单独的动画帧。 内层循环设置两个偏振值。x轴偏振使用sin函数。y轴偏振也是正弦波,但其相对x轴的偏振是一个0-3的随机值,初始偏振值是一个零值,随着动画的每一帧逐渐增加。循环会一直跑到x轴完成五次完整的循环。每一步它都会调用SetColorIndex来为(x,y)点来染黑色。

结束语

第四小节的学习到此结束。