Erlang 映射 (Map)

2022-07-07 15:37 更新

Erlang映射 (Map)

映射用于表示鍵和值的關聯(lián)關系。這種關聯(lián)方式是由 “#{” 與 “}” 括起來。創(chuàng)建一個字符串 "key" 到值 42 的映射的方法如下:

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

讓我們直接通過示例來看一些有意思的特性。

下面的例子展示了使用映射來關聯(lián)顏色與 alpha 通道,從而計算 alpha 混合(譯注:一種讓 3D 物件產(chǎn)生透明感的技術)的方法。將下面的代碼輸入到 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).

編譯并測試:

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

關于上面的例子的解釋如下:

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

首先,上面的例子中定義了一個宏 is_channel,這個宏用的作用主要是方便檢查。大多數(shù)情況下,使用宏目的都是為了方便使用或者簡化語法。更多關于宏的內容可以參考預處理

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

函數(shù) new/4 創(chuàng)建了一個新的映射,此映射將 red,green,blue 以及 alpha 這些健與初始值關聯(lián)起來。其中,is_channel 保證了只有 0.0 與 1.0 之間的浮點數(shù)是合法數(shù)值 (其中包括 0.0 與 1.0 兩個端點值)。注意,在創(chuàng)建新映射的時候只能使用 => 運算符。

使用由 new/4 函數(shù)生成的任何顏色作為參數(shù)調用函數(shù) blend/2,就可以得到該顏色的 alpha 混合結果。顯然,這個結果是由兩個映射來決定的。

blend/2 函數(shù)所做的第一件事就是計算 alpha 通道:

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

使用 := 操作符取得鍵 alpha 相關聯(lián)的值作為參數(shù)的值。映射中的其它鍵被直接忽略。因為只需要鍵 alpha 與其值,所以也只會檢查映射中的該鍵值對。

對于函數(shù) red/2,blue/2 和 green/2 也是一樣的:

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

唯一不同的是,每個映射參數(shù)中都有兩個鍵會被檢查,而其它鍵會被忽略。

最后,讓我們回到 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 映射會被更新為一個新的通道值。更新已存在的映射鍵值對可以用 := 操作符。

以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號