现代c++开发利器folly教程系列之:dynamic
2019独角兽企业重金招聘Python工程师标准>>>
一、前言
用过python、php等动态类型语言的人肯定对动态数据类型不陌生。对于定义时不确定、运行时才确定的数据类型,使用动态类型是非常方便的。c++是一门不折不扣的静态类型语言,那么是否就无缘享受“动态”类型的好处了呢?不尽然。folly为我们提供了dynamic类型,从一定程度上实现了c++中的“动态”数据类型,为什么说是“一定程度上”呢,因为dynamic类型只支持c++中的基本类型(部分)和复合类型(array和map),不支持自定义类型。你可能会把dynamic和boost::any或std::any(将在c++17中支持)进行对比,但是其实它们没有可比性,首先是它们的实现原理不同。boost::any虽然可以盛放任何类型,但是它在实现上是用继承的方式进行了类型擦除,因此在还原类型时,需要程序员自己显示的提供类型信息,这也是boost::any的缺点之一。而dynamic虽然代表的类型有限,但是dynamic本身可以记住类型,便于赋值和还原。因此,dynamic不是boost::any的替代品,更像是一种补充,如果非要类比的话,dynamic和boost::variant更为相似。
二、类型支持
如前文所述,dynamic可以盛放的类型是有限的,它可以盛放部分基本类型、字符串类型、数组类型和OBJECT(本质为map)类型,具体支持的类型如下:
enum Type {NULLT,ARRAY,BOOL,DOUBLE,INT64,OBJECT,STRING,};
可以看到,在整型支持方面,dynamic只支持最宽的整型INT64,而没有对其他整型进行细分,其实这个可以理解,最大整型都支持了,其它的类型就不在话下了,缺点无非就是浪费一点内存了。ARRAY类型就是经常使用的数组,不同的是,这里的数组的元素类型也为dynamic,同样,OBJECT类型就是一个map类型(为什么叫OBJECT呢,OBJECT的中文为对象的意思,而一个对象本质上是由一个个的key-value属性键值对构成的),这个map的key和value都为dynamic类型。
三、基本用法
1、赋值(初始化)
直接看一段应用代码:
dynamic twelve = 12; // creates a dynamic that holds an integer// STRING类型dynamic str = "string"; // NULL类型dynamic nul = nullptr;// BOOL类型dynamic boolean = false;// ARRAY类型dynamic array = dynamic::array("array ", "of ", 4, " elements");assert(array.size() == 4);dynamic emptyArray = dynamic::array;assert(emptyArray.empty());// 使用dynamic::objec可以构造一个空的mapdynamic map = dynamic::object;map["something"] = 12;map["another_something"] = map["something"] * 2;// 也可以在构造的时候直接初始化一个mapdynamic map2 = dynamic::object("something", 12)("another_something", 24);
可以看到,虽然dynamic在类型支持上是有限的,但是通过组合、搭配可以满足日常开发中的绝大多数场景。
除了类型之外,如果在赋值时使用了dynamic不支持的非法运算符操作,有可能会抛出folly::TypeError错误。例如:
dynamic dint = 42;dynamic str = "foo";dynamic anotherStr = str + "something"; // finedynamic thisThrows = str + dint; // 将字符串与整形相加 TypeError is raised
2、取值
dynamic最大的优点就是它可以记得自己存储的数据类型,那么如何获得类型呢?dynamic提供了类型获取api,如下:
/** Returns true if this dynamic is of the specified type.*/bool isString() const;bool isObject() const;bool isBool() const;bool isNull() const;bool isArray() const;bool isDouble() const;bool isInt() const;/** Returns: isInt() || isDouble().*/bool isNumber() const;/** Returns the type of this dynamic.*/Type type() const;
常见用法如下:
dynamic str = "my name is cy";
assert(str.isString());dynamic integer = 123;
assert(integer.isInt());dynamic map = dynamic::object;
assert(map.isObject());
这只是类型判断,并没有进行取值操作,取值操作同样有相应的api,如下:
/** Extract a value while trying to convert to the specified type.* Throws exceptions if we cannot convert from the real type to the* requested type.** Note you can only use this to access integral types or strings,* since arrays and objects are generally best dealt with as a* dynamic.*/std::string asString() const;double asDouble() const;int64_t asInt() const;bool asBool() const;/** Extract the value stored in this dynamic without type conversion.** These will throw a TypeError if the dynamic has a different type.*/const std::string& getString() const&;double getDouble() const&;int64_t getInt() const&;bool getBool() const&;std::string& getString() &;double& getDouble() &;int64_t& getInt() &;bool& getBool() &;std::string&& getString() &&;double getDouble() &&;int64_t getInt() &&;bool getBool() &&;
从上面的注释可以清晰的看到,以get开头的api会原样提取dynamic存储的值,一旦类型不匹配,就会抛出TypeError异常,而以as开头的api带有类型转换的意思,比如dynamic本身存储了一个整型,但是可以将其as字符串的形式取出来,例如:
dynamic dint = 12345678;auto integer = dint.getInt();//done
auto str = dint.getString();// TypeError
auto str2 = dint.asString();// done
三、遍历
1、数组遍历
数组的遍历和正常的foreach遍历是一样的:
dynamic array = dynamic::array(2, 3, "foo");for (auto val : array) {doSomethingWith(val);}
2、map遍历
OBJECT(map)的遍历稍微复杂一点,需要注意的是,不能直接遍历一个OBJECT,而是先要使用items()方法取出dynamic内部真正的map才可以,同样,如果想要单独遍历key或者value,则只要使用dynamic的keys和values方法即可:
dynamic obj = dynamic::object(2, 3)("hello", "world")("x", 4);for (auto pair : obj.items()) {// Key is pair.first, value is pair.secondprocessKey(pair.first);processValue(pair.second);}// 单独遍历keyfor (auto key : obj.keys()) {processKey(key);}// 单独遍历valuefor (auto value : obj.values()) {processValue(value);}
关于map的查找,它提供了和stl兼容的find方法,比如:
dynamic obj = dynamic::object(2, 3)("hello", "world")("x", 4);auto pos = obj.find("hello");// pos->first is "hello"// pos->second is "world"auto pos = obj.find("no_such_key");// pos == obj.items().end()
其实在实际应用中,OBJECT就是一个kv存储(内存),经常需要判断一个key是否在缓存中,使用上面的find方法还是比较麻烦的,我更推荐使用get_ptr方法,比如我想判断OBJECT中是否存在一个名为“age”的键值对,如果存在就取出这个age值(职位INT64类型),代码如下:
dynamic obj = dynamic::object("age", 28);auto age_ptr = obj.get_ptr("age");if(age_ptr){auto age = age_ptr->asInt();}
当OBJECT中不包含对象的key时,get_ptr将返回一个nullptr。
四、JSON序列化、反序列化
folly为dynamic提供了内置的json支持,这对于经常使用json进行序列化和反序列化的应用而言非常强大和方便(再也不用使用jsoncpp这么难用的库了),序列化和反序列化接口很简单,定义如下:
/** Serialize a dynamic into a json string.*/
std::string toJson(dynamic const&);
/** Parse a json blob out of a range and produce a dynamic representing* it.*/
dynamic parseJson(StringPiece, json::serialization_opts const&);
dynamic parseJson(StringPiece);
直接看个例子:
// 先定义一个json字符串std::string jsonDocument = R"({"key":12,"key2":[false, null, true, "yay"]})";// 执行json反序列化,反序列化结果为dynamicdynamic parsed = folly::parseJson(jsonDocument);assert(parsed["key"] == 12);assert(parsed["key2"][0] == false);assert(parsed["key2"][1] == nullptr);// 构建一个OBJECTdynamic sonOfAJ = dynamic::object("key", 12)("key2", dynamic::array(false, nullptr, true, "yay"));// json序列化auto str = folly::toJson(sonOfAJ);assert(jsonDocument.compare(str) == 0);
本系列文章
现代c++开发利器folly教程系列之:future/promise
现代c++开发利器folly教程系列之:dynamic
转载于:https://my.oschina.net/fileoptions/blog/883002
现代c++开发利器folly教程系列之:dynamic相关推荐
- 【转】现代c++开发利器folly教程系列之:future/promise
一.前言 promise/future是一个非常重要的异步编程模型,它可以让我们摆脱传统的回调陷阱,从而使用更加优雅.清晰的方式进行异步编程.c++11中已经开始支持std::future/std:: ...
- folly教程系列之:future/promise
attension:本文严禁转载. 一.前言 promise/future是一个非常重要的异步编程模型,它可以让我们摆脱传统的回调陷阱,从而使用更加优雅.清晰的方式进行异步编程.c++11中 ...
- Java学习开发入门基础教程系列
ava是一种跨平台的语言,一次编写,到处运行,在世界编程语言排行榜中稳居第二名(第一名是C语言). Java用途广泛,可以用来开发传统的客户端软件和网站后台,也可以开发如火如荼 Android 应用和 ...
- web前端开发入门基础教程系列
前端工程师是互联网时代软件产品研发中不可缺少的一种专业研发角色.从狭义上讲,前端工程师使用 HTML.CSS.JavaScript 等专业技能和工具将产品UI设计稿实现成网站产品,涵盖用户PC端.移动 ...
- [转载]Python量化交易平台开发教程系列0-引言
原文出处:http://vnpy.org/2015/03/04/20150304_Python%E9%87%8F%E5%8C%96%E4%BA%A4%E6%98%93%E5%B9%B3%E5%8F%B ...
- webgis从基础到开发实践_开源WebGIS教程系列——11.1 GISLite 的开发背景与设计
地理信息门户可以帮助人们更容易地发现.访问和使用地理空间信息, 是地理信息发布.服务和共享的重要环节.许多国家都很重视地理信息门户的 建设,把它作为国家空间数据基础设施(spatial data in ...
- java建站系统开发教程系列之设计表结构
java建站系统开发教程系列之设计表结构 根据需求设计表结构如下: SET FOREIGN_KEY_CHECKS=0; -- Table structure for tbl_articles -- - ...
- Python量化交易平台开发教程系列0-引言
原创文章,转载请注明出处:用Python的交易员 为什么用Python来开发量化交易平台 目前本人所在的公司一共有三款平台,分别基于C++, C#和Python.其中C#和Python平台都是由交易员 ...
- Python量化交易平台开发教程系列1-类CTP交易API的工作原理
原创文章,转载请注明出处:用Python的交易员 类CTP交易API简介 国内程序化交易技术的爆发式发展几乎就是起源于上期技术公司基于CTP柜台推出了交易API,使得用户可以随意开发自己的交易软件直接 ...
最新文章
- 列表转字符串,再转回来,完全一致
- 【Discuz】云平台服务:出了点小错,由于站点ID/通信KEY等关键信息丢失导致Discuz!云平台服务出现异常
- 二、通过工厂方法来配置bean
- IBM向客户发放了一批“染毒”的U盘,现紧急建议物理销毁
- RealSense开发-Session和SenseManager的几种创建方法
- nfs:client mount成功,但是进入目录时出现Permission denied
- 抖音数据统计_26万条抖音数据背后的推荐逻辑以及严重失调的男女比例
- 虎年第一篇-CCNP-第九篇-BGP(一)
- C#6.0VISUALSTUDIO 2015 C#入门经典 第7版pdf
- 【鱼眼镜头2】[鱼眼畸变模型]:评估了五个模型:radial,division,FOV,多项式(如双三次]和rational模型。
- Linux系统基础原理
- 天线接口 IPEX接口 SMA接口 U.FL、IPX 天线的工作原理 天线的种类
- math.js api static function
- 台式计算机开关电源原理图,计算机开关电源基本结构及原理
- 一文了解Clickhouse
- 游标CURSOR的基本用法
- java中不可变对象(immutable object)是什么,有什么意义
- 笛卡尔的思维法则(数学思维的规范)
- 你真的了解IP地址吗?
- 基于空间平滑MUSIC算法的相干信号DOA估计(2)
热门文章
- Spring Boot - Font Awesome OTS parsing error: Failed to convert( Failed to decode downloaded font)
- Office2016打开Word时点击保存弹出“word无法启动转换器RECOVR32.CNV”对话框问题解决
- 女生学UI还是软件测试好?
- 如何使用SQL中的条件计算每月的总销售额?
- 程序员该如何逃离困境
- 在微信的视频通话中将语音转成文字并显示在通话界面中,可以使用语音识别技术,将语音转换成文本,再通过编程技巧将文本显示在通话界面中。在手机上实现方法代码...
- 开发效率必备之Mac双屏显示
- 埃森哲:新媒体时代的精准营销
- 用html编写一个红绿灯,如何用html+css+javascript写一个简易红绿灯
- vue 地理位置定位_cordova+vue webapp 使用html5获取地理位置