现代c++开发利器folly教程系列之:dynamic
2017-04-20 19:00
531 查看
一、前言
用过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可以构造一个空的map dynamic map = dynamic::object; map["something"] = 12; map["another_something"] = map["something"] * 2; // 也可以在构造的时候直接初始化一个map dynamic map2 = dynamic::object("something", 12)("another_something", 24);
可以看到,虽然dynamic在类型支持上是有限的,但是通过组合、搭配可以满足日常开发中的绝大多数场景。
除了类型之外,如果在赋值时使用了dynamic不支持的非法运算符操作,有可能会抛出folly::TypeError错误。例如:
dynamic dint = 42; dynamic str = "foo"; dynamic anotherStr = str + "something"; // fine dynamic 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.second processKey(pair.first); processValue(pair.second); } // 单独遍历key for (auto key : obj.keys()) { processKey(key); } // 单独遍历value for (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反序列化,反序列化结果为dynamic dynamic parsed = folly::parseJson(jsonDocument); assert(parsed["key"] == 12); assert(parsed["key2"][0] == false); assert(parsed["key2"][1] == nullptr); // 构建一个OBJECT dynamic 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
相关文章推荐
- 现代c++开发利器folly教程系列之:future/promise
- Red Gate系列之三 SQL Server 开发利器 SQL Prompt 5.3.4.1 Edition T-SQL智能感知分析器 完全破解+使用教程
- ABP(现代ASP.NET样板开发框架)系列之2、ABP入门教程
- 基于DDD的现代ASP.NET开发框架--ABP系列之2、ABP入门教程
- Red Gate系列之三 SQL Server 开发利器 SQL Prompt 5.3.4.1 Edition T-SQL智能感知分析器 完全破解+使用教程
- ABP(现代ASP.NET样板开发框架)系列之二、ABP入门教程详解
- Red Gate系列之三 SQL Server 开发利器 SQL Prompt 5.3.4.1 Edition T-SQL智能感知分析器 完全破解+使用教程
- 基于DDD的现代ASP.NET开发框架--ABP系列之2、ABP入门教程
- Red Gate系列之三 SQL Server 开发利器 SQL Prompt 5.3.4.1 Edition T-SQL智能感知分析器 完全破解+使用教程
- [导入]如何使用Thinkphp快速开发 系列教程(1)
- C#开发团队的《Future Focus》系列文章,以及第一篇中介绍的动态查找(Dynamic Lookup)
- Visual Studio 2008开发新特性系列课程(12):团队协作开发利器——VSTS2008新特性展示
- Ruby on rails开发从头来系列教程(附ruby电子书下载)
- mos开发系列教程十:说明
- 轻松掌握Ajax.net系列教程十一:使用DynamicPopulateExtender
- C++开发环境格局难打破 75%的开发人员首选VS系列
- 系列教程:DB2 9 应用开发(733)认证指南
- 挑战30天C/C++ 入门极限系列教程
- MapGuide open source开发系列教程五: 屏幕坐标与地图坐标(问题)已修改