Erlang入门教程 - 6. Maps

racaljkracaljk

Maps是一堆键值关联对的集合。键值对使用 “#{” 和”}”进行封装。要创建一个key关联value 42可以这么做:

> #{ "key" => 42 }.
#{"key" => 42}

让我们通过下面这个使用有趣特性的例子直接跳到一个深度。

下面的例子显示了如何通过maps引用颜色和α通道进而计算α混合(alpha blending)。在color.erl文件中输入下面代码:

-module(color).

-export([new/4, blend/2]).

-define(is_channel(V), (is_float(V) andalso V >= 0.0 andalso V =< 1.0)).

new(R,G,B,A) when ?is_channel(R), ?is_channel(G),
                  ?is_channel(B), ?is_channel(A) ->
    #{red => R, green => G, blue => B, alpha => A}.

blend(Src,Dst) ->
    blend(Src,Dst,alpha(Src,Dst)).

blend(Src,Dst,Alpha) when Alpha > 0.0 ->
    Dst#{
        red   := red(Src,Dst) / Alpha,
        green := green(Src,Dst) / Alpha,
        blue  := blue(Src,Dst) / Alpha,
        alpha := Alpha
    };
blend(_,Dst,_) ->
    Dst#{
        red   := 0.0,
        green := 0.0,
        blue  := 0.0,
        alpha := 0.0
    }.

alpha(#{alpha := SA}, #{alpha := DA}) ->
    SA + DA*(1.0 - SA).

red(#{red := SV, alpha := SA}, #{red := DV, alpha := DA}) ->
    SV*SA + DV*DA*(1.0 - SA).
green(#{green := SV, alpha := SA}, #{green := DV, alpha := DA}) ->
    SV*SA + DV*DA*(1.0 - SA).
blue(#{blue := SV, alpha := SA}, #{blue := DV, alpha := DA}) ->
    SV*SA + DV*DA*(1.0 - SA).

编译并测试:

> c(color).
{ok,color}
> C1 = color:new(0.3,0.4,0.5,1.0).
#{alpha => 1.0,blue => 0.5,green => 0.4,red => 0.3}
> C2 = color:new(1.0,0.8,0.1,0.3).
#{alpha => 0.3,blue => 0.1,green => 0.8,red => 1.0}
> color:blend(C1,C2).
#{alpha => 1.0,blue => 0.5,green => 0.4,red => 0.3}
> color:blend(C2,C1).
#{alpha => 1.0,blue => 0.38,green => 0.52,red => 0.51}


This example warrants some explanation:

-define(is_channel(V), (is_float(V) andalso V >= 0.0 andalso V =< 1.0)).

首先定义一个宏is_channel用于guard测试。为了方便起见这里使用它减少语法的杂糅。关于宏的更多信息,参见Preprocessor[8]。

new(R,G,B,A) when ?is_channel(R), ?is_channel(G),
                  ?is_channel(B), ?is_channel(A) ->
    #{red => R, green => G, blue => B, alpha => A}.

函数new/4创建一个map并且让键red,green,blue,alpha关联一个初始值。 在这里, 将宏?is_channel作用于每个参数,确保只有0.0到1.0之间的浮点值才被允许,只有在创建新map的时候才允许使用=>运算符。

使用new/4创建一个color,然后将colors传递给blend/2,它就能计算出混合后的颜色。

首先blend/2做的事是计算混合后的α通道

alpha(#{alpha := SA}, #{alpha := DA}) ->
    SA + DA*(1.0 - SA).

使用:=运算符获取参数中键alpha所关联的value。参数中的其他键会被忽略掉,只要求键alpha。
函数red/2, blue/2,green/2也是如此:

red(#{red := SV, alpha := SA}, #{red := DV, alpha := DA}) ->
    SV*SA + DV*DA*(1.0 - SA).

这里不同点是这几个函数获取参数中的两个键,其它的被忽略。

最后,让我们在blend/3中返回混合后的颜色:

blend(Src,Dst,Alpha) when Alpha > 0.0 ->
    Dst#{
        red   := red(Src,Dst) / Alpha,
        green := green(Src,Dst) / Alpha,
        blue  := blue(Src,Dst) / Alpha,
        alpha := Alpha
    };

Dst使用新通道值进行更新。更新一个已有的键关联的值的语法是使用:=运算符。

文章被以下专栏收录
还没有评论
推荐阅读