元组是用来保存一组数据元素的复合数据类型,其中数据元素是要求为erlang的数据类型,单不一定要是相同的类型,元组使用封闭的花括号{}来定义,里面的元素有逗号隔开。

  例如: 1> {1,2,3}.

      2> {1,{2,3},4}.

      3> {1,[2,3],4}.

      4> {1,"23",4}.

  tuple 的bifs函数:

  erlang:tuple_size(Tuple) ->Length. Tuple 的长度

  erlang:element(i,Tuple) -> aton(). 选择第i个位置的元素

  erlang:setelement(i,Tuple,Aton) ->Tuple2, 修改Tuple中的第i个位置的值为Aton。

  参考lists,得出一些类似lists的函数:

-module(com_record).

%% ====================================================================
%% API functions
%% ====================================================================
-export([map/2,
get_name/1,
foreach/2,
foldl/3,
foldl2/4,
foldl_index/4,
merge/3,
merge/4,
any/2,
any/3,
tuple_merge/3,
put_pd_fields/2,
get_pd_fields/2
]).

-spec any(Pred, T) -> boolean() when
Pred :: fun((Elem::term() ) -> boolean()),
T :: tuple().

%% @doc like lists:any/1
any(Pred, Tuple) ->
any(Pred, Tuple, 2).

any(_, {}, _) -> false;
any(Pred, Tuple, Begin) ->
S = tuple_size(Tuple),
if S < Begin ->
false;
true ->
any__(Pred, Tuple, Begin, S)
end.

any__(Pred, Tuple, M, M) ->
Pred(element(M, Tuple));
any__(Pred, Tuple, N, M) ->
case Pred(element(M, Tuple)) of
true ->
true;
_ ->
any__(Pred, Tuple, N+1, M)
end.

%% @doc record map
-spec map(Func, Record) -> Record2 when
Record :: Tuple,
Record2 :: Tuple,
Func :: fun((term()) -> term()),
Tuple :: tuple().
map(Func, Record) ->
[Name| List] = erlang:tuple_to_list(Record),
List2 = lists:map(Func, List),
erlang:list_to_tuple([Name | List2]).

-compile({inline, [get_name/1]}).
%% @doc get record name.
-spec get_name(tuple()) -> atom().
get_name(Record) ->
erlang:element(1, Record).

%% @doc foreach element not include name.
-spec foreach(Fun, Record) -> ok when
Fun :: fun((term()) -> _),
Record :: tuple().
foreach(Fun, Record) when is_tuple(Record) ->
com_util:for(2, erlang:tuple_size(Record), Fun).

%% @doc foldl element not include name.
-spec foldl(Fun, Acc0, Record) -> Acc1 when
Fun :: fun((term(), AccIn) -> AccOut),
Acc0 :: term(),
Acc1 :: term(),
AccIn :: term(),
AccOut :: term(),
Record :: tuple().

%% @doc not aceess record name.
foldl(Func, Acc, Record) when is_function(Func,2) ->
case erlang:tuple_size(Record) of
1 -> Acc;
M ->
foldl_(Func, Acc, Record, 2, M)
end.

foldl2(Func, Acc, Record, Begin)
when is_function(Func, 2) ->
case erlang:tuple_size(Record) of
S when S < Begin -> Acc;
S ->
foldl_(Func, Acc, Record, Begin, S)
end.

foldl_(Func, Acc, Record, N, N) ->
Func(erlang:element(N, Record), Acc);
foldl_(Func, Acc, Record, N, M) ->
foldl_(Func,
Func(erlang:element(N, Record), Acc),
Record, N+1, M).

%% @doc same foldl2 but fun take 3 arg
foldl_index(Func, Acc, Record, Begin) ->
case erlang:tuple_size(Record) of
S when S < Begin -> Acc;
S ->
foldl_index_(Func, Acc, Record, Begin, S)
end.

%% @doc merge two same type record with func
%% two record must same type.
%% Fun argument is record elements
%% @usage
%% merage(fun(A,B) -> A + B end, {aa, 1,1,1} , {aa, 3,3,3})
%% -> {aa, 4,4,4}
-spec merge(Fun, Record1, Record2) -> RecordOut when
Fun :: fun((A, B) -> T),
Record1 :: RecordOut,
Record2 :: RecordOut,
RecordOut :: tuple(),
A :: term(),
B :: term(),
T :: term().

merge(Fun, Record1, Record2) when is_function(Fun, 2) ->
merge__(Fun, Record1, Record2, 2, {get_name(Record1)}).

merge(Fun, Record1, Record2, Begin) when is_function(Fun, 2) ->
merge__(Fun, Record1, Record2, Begin, {get_name(Record1)}).

tuple_merge(Fun, T1, T2) ->
merge__(Fun, T1, T2, 1, {}).

merge__(Fun, T1, T2, Begin, Acc) ->
com_util:fold(Begin,
erlang:tuple_size(T1),
fun(Index, RecordOut) ->
erlang:append_element(RecordOut,
Fun(erlang:element(Index, T1),
erlang:element(Index, T2)))
end,
Acc
).

foldl_index_(Func, Acc, Record, N, N) ->
Func(N, erlang:element(N, Record), Acc);
foldl_index_(Func, Acc, Record, N, M) ->
foldl_index_(Func,
Func(N, erlang:element(N, Record), Acc),
Record, N+1, M).

%% HACK 最好的元转换
%% @doc 存入进程字典 每个filed 都会在前面加上pd_ 的前缀
%% 每个进程字典都只能是单次赋值
put_pd_fields(Record, FieldsName)
when erlang:is_list(FieldsName),
erlang:is_tuple(Record) ->
lists:foldl(fun(FName, Index) ->
case erlang:put(erlang:list_to_atom("pd_" ++ erlang:atom_to_list(FName)),
erlang:element(Index, Record))
of
undefined -> ok;
Ov -> io:format("ERR recrod_put ~p not first ~p\n", [FName, Ov])
end,
Index+1
end,
2,
FieldsName).

%% @doc Record
-spec get_pd_fields(RecordName, [atom()]) -> RecordOut when
RecordName :: atom(),
RecordOut :: tuple().

get_pd_fields(RecordName, FieldsName)
when erlang:is_list(FieldsName) ->
lists:foldl(fun(FName, R) ->
erlang:append_element(R,
erlang:get(erlang:list_to_atom("pd_" ++ erlang:atom_to_list(FName))))
end,
{RecordName},
FieldsName).

%%%%%% TEST unit

%-define(TEST, 1).
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").

-record(tt, {id, name, age}).

pd_fields_test() ->
R= #tt{id=32, name= <<"feof">>, age=[1,2,4]},
put_pd_fields(R, record_info(fields, tt)),
?assertEqual(32, get(pd_id)),
?assertEqual(<<"feof">>, get(pd_name)),
?assertEqual([1,2,4], get(pd_age)),

R2 = get_pd_fields(tt, record_info(fields, tt)),
?assertEqual(R2, R),

ok.

-endif.

j教你如何用erlang-tuple的更多相关文章

  1. 教你如何用PS制作多款按钮UI设计教程

    教你如何用PS制作多款按钮UI设计教程 本文教大家制作按钮的方法 LV. ★ 初入设计,学做按钮.只会套个底色,加个阴影,字体纯白,小聪明的弄个圆角. LV. ★★(描边.字体.内阴影) 看了很多案例 ...

  2. 说说erlang tuple和record结构

    erlang有两种复合结构.tuple和list,两者的区别是tuple子元素的个数是固定不变的.声明后就不能改变了.而list是可变的,能够通过[H|T]来取出或插入新元素. record有点像C/ ...

  3. 从原理到代码:大牛教你如何用 TensorFlow 亲手搭建一套图像识别模块 | AI 研习社

    从原理到代码:大牛教你如何用 TensorFlow 亲手搭建一套图像识别模块 | AI 研习社 PPT链接: https://pan.baidu.com/s/1i5Jrr1N 视频链接: https: ...

  4. 一篇文章教你如何用R进行数据挖掘

    一篇文章教你如何用R进行数据挖掘 引言 R是一种广泛用于数据分析和统计计算的强大语言,于上世纪90年代开始发展起来.得益于全世界众多 爱好者的无尽努力,大家继而开发出了一种基于R但优于R基本文本编辑器 ...

  5. 零元学Expression Design 4 - Chapter 5 教你如何用自制笔刷在5分钟内做出设计感效果

    原文:零元学Expression Design 4 - Chapter 5 教你如何用自制笔刷在5分钟内做出设计感效果 本章将教你如何运用笔刷与简单线条,只要5分钟,就能做出设计感效果 ? 本章将教你 ...

  6. Android | 教你如何用华为HMS MLKit 图像分割 SDK开发一个证件照DIY小程序

    Android | 教你如何用华为HMS MLKit 图像分割 SDK开发一个证件照DIY小程序 引子   上期给大家介绍了如何使用如何用华为HMS MLKit SDK 三十分钟在安卓上开发一个微笑抓 ...

  7. Android | 教你如何用代码一键实现银行卡绑定

    前言   小编前面几期文章分别给大家介绍了用代码实现微笑抓拍.证件照DIY.拍照翻译的功能开发(链接见文章末尾),本次小编给大家带来的是用代码一键实现银行卡识别与绑定功能. 银行卡识别的应用场景    ...

  8. 手把手教小白如何用css+js实现页面中图片放大展示效果

    1.前言      很多童鞋会在项目中遇到一些上传图片,展示图片的操作,但是图片呢有大有小,为了页面的美观,有时候我们需要将图片展示成固定宽高度,但是呢,领导就会说,我想看大图片,怎么办?想看就看呀, ...

  9. 一篇文章教你如何用 Python 记录日志

    前言: 这篇文章是我copy别人的,但是个人认为讲的真的很细致,有原理有实例,不仅仅只教你如何使用日志更会叫你知道日志的原理,真的非常棒,虽然文章很长,也许你不会认认真真读完, 但是当你遇到问题时这篇 ...

随机推荐

  1. iptables 初见 第一章

    官网:https://www.netfilter.org/ 简单来来说 ,netfilter 是一个工作在内核空间的数据包过滤系统,iptables 是一个工作在用户控件.调用netfilter 的规 ...

  2. Docker Swarm 环境搭建

    Docker Swarm 环境搭建 swarm 使用前提 1.Docker版本1.12+ Docker升级教程:https://www.cnblogs.com/xiangsikai/p/9935894 ...

  3. 11个简单的Java性能调优技巧,傻瓜都能学会!

    大多数开发人员理所当然地以为性能优化很复杂,需要大量的经验和知识.好吧,不能说这是完全错误的.优化应用程序以获得最佳性能不是一件容易的事情.但是,这并不意味着如果你不具备这些知识,就不能做任何事情. ...

  4. 【Alpha】Scrum Meeting 2

    前言 第2次会议在3月28日由PM在教一317召开. 主要确定了项目方向和目标功能,进行了任务分工.时长60min. 任务分配 姓名 当前阶段任务 下阶段任务 吴昊 熟悉代码和配置环境,发布手机端博客 ...

  5. 4、zabbix基本配置入门

    Zabbix监控流程: Host group --> Hosts(向server端添加被监控主机) --> Application(在agent定义) --> Items(在appl ...

  6. vue--音乐播放器

    github: https://github.com/vinieo/vue-music 效果: 基础组件: 1.confirm:确认对话框组件 2.listview:通讯录列表组件 3.loading ...

  7. Qt5OpenGL.术语01

    来自:QT 5.4+ OpenGL编程 - brain2004的专栏 - CSDN博客.html(https://blog.csdn.net/brain2004/article/details/707 ...

  8. 力扣(LeetCode)482. 密钥格式化

    给定一个密钥字符串S,只包含字母,数字以及 '-'(破折号).N 个 '-' 将字符串分成了 N+1 组.给定一个数字 K,重新格式化字符串,除了第一个分组以外,每个分组要包含 K 个字##符,第一个 ...

  9. JS中for in 与 for of

    // 数组var A=[4,6,74,67]; for in:拿到的是数组下标 for (let i in A){ console.log(i); } //0,1,2,3 for of:拿到的是数组元 ...

  10. 更改ssh,ftp默认端口

    1.  更改ssh端口 放置升级openssh之后做此步骤 配置文件/etc/ssh/sshd_config 注释掉Subsystem      sftp    /usr/libexec/openss ...