| 
 | 
 
没有上一篇 
 
这一篇:受苦过程(一) 
 
下一篇:受苦过程(二) 
 
玩具项目想要一个json类,干脆自己写个玩,于是记录一下可能的受苦过程,做到哪写到哪。 
首先写个json库就要明确这个库究竟要干哪些事,这些事写道代码是什么样的,具体库用起来怎么用的? 
那么根据Milo Yip:从零开始的 JSON 库教程中给的总结,可以概况成一下三种情况 
 
- 解析json字符串为json类
 
 - 获取json值
 
 - 把一个对象json化
 
  那么具体用起来应该像下面这样 
/* 
        // get json 
        Json json("file.json"); 
        // or 
        Json json; 
        json.read("file.json"); 
        // or 
        ClassCanToJson cls; 
        Json json(cls); 
        // or  
        Json json = cls.toJson(); 
 
        // get value 
        auto val = json["key"]; 
        std::cout<<val<<std::endl; 
 
        // to json file 
        json.dump(output_file_path); 
*/那么要做到这种效果需要Json类解析json文件,存储json的值,获取json值,同时需要将存储的值转化为json格式。 
 
那Json类长得就该像这样 
// Json.h 
#pragma once 
#include&#34;Node.h&#34; 
class Json; 
class CanJson 
{ 
public: 
        virtual Json toJson() = 0; 
}; 
class Json 
{ 
public: 
        Json():jsons(std::make_shared<JsonArray>()){}; 
        ~Json() {}; 
        Json(const Json & js):jsons(js.jsons) {}; 
        Json(Json && js) :jsons(js.jsons) {}; 
        Json(const CanJson & cls) {}; 
        void addNode(const JsonNode & jn) 
        { 
                jsons->insert(jn); 
        } 
        void parse(const std::string_view & s) {}; 
        void read(const std::string & file_path) {}; 
        void dump() {}; 
        auto operator [](const std::string & s) 
        { 
                auto find_ret = jsons->find(JsonNode(s)); 
                if (find_ret == jsons->end()) 
                        throw std::runtime_error(&#34;wrong [] key is: &#34; + s); 
                return *find_ret; 
        } 
        std::string toString()const 
        { 
                std::string result; 
                result += &#34;{\n&#34;; 
                for (auto & node : *jsons) 
                { 
                        result.push_back(&#39;\t&#39;); 
                        result += node.toString(); 
                        result.push_back(&#39;,&#39;); 
                        result.push_back(&#39;\n&#39;); 
                } 
                result.pop_back(); 
                result.pop_back(); 
                result += &#34;\n}\n&#34;; 
                return result; 
        } 
private: 
        std::shared_ptr<JsonArray> jsons; 
}; 
值可以用一个variant存,我这里用了一个比较蠢的抽象,在创建节点的时候传一个array_type,如果为真那就真的是json的array类型同时key为空,如果为假视为json类型key非空,于是就不支持key为&#34;&#34;。用std::vistit来试存哪个类型。 
// JsonValues.h 
#pragma once 
#include<string> 
#include<set> 
#include<variant> 
#include<iostream> 
#include&#34;Node.h&#34; 
enum JSONTYPE:int { NULL_TYPE, BOOL_TYPE, NUMBER_TYPE,STRING_TYPE, ARRAY_TYPE, JSON_TYPE ,NO_TYPE = -1}; 
class JsonNode; 
using String = std::string; 
using Null = std::monostate; 
using JsonArray = std::multiset <JsonNode>; 
using Value = std::variant<Null, bool, double, String, JsonArray>; 
 
struct JsonValue 
{ 
        JsonValue() {}; 
        JsonValue(const Value &&val) :__value(std::move(val)) {} 
        JsonValue(const Value &&val, bool array_type) 
                :__value(std::move(val)), array_type(array_type) {} 
        JsonValue(const JsonValue & v) 
                :__value(v.__value), array_type(v.array_type), type(v.type){} 
        JsonValue(JsonValue && v) 
                :__value(std::move(v.__value)), array_type(v.array_type), type(v.type) {} 
        Value __value = std::monostate{}; 
        bool array_type = false; 
        JSONTYPE type = JSONTYPE::NO_TYPE; 
        JSONTYPE getType() 
        { 
                if (type != JSONTYPE::NO_TYPE) 
                        return type; 
                std::visit( 
                        [&](auto && arg) 
                        { 
                                using T = std::decay_t<decltype(arg)>; 
                                if constexpr (std::is_same_v<T, double>) 
                                { 
                                        this->type = JSONTYPE::NUMBER_TYPE; 
                                } 
                                else if constexpr (std::is_same_v<T, String>) 
                                { 
                                        this->type = JSONTYPE::STRING_TYPE; 
                                } 
                                else if constexpr (std::is_same_v<T, Null>) 
                                { 
                                        this->type = JSONTYPE::NULL_TYPE; 
                                } 
                                else if constexpr (std::is_same_v<T, bool>) 
                                { 
                                        this->type = JSONTYPE::BOOL_TYPE; 
                                } 
                                else if constexpr (std::is_same_v<T, JsonArray>) 
                                { 
                                        this->type = this->array_type ? JSONTYPE::ARRAY_TYPE : JSONTYPE::JSON_TYPE; 
                                } 
                        }, __value); 
                return type; 
        } 
        std::string toString()const 
        { 
                std::string result; 
                std::visit( 
                        [&](auto && arg) 
                        { 
                                using T = std::decay_t<decltype(arg)>; 
                                if constexpr (std::is_same_v<T, double>) 
                                { 
                                        result += std::to_string(arg); 
                                } 
                                else if constexpr (std::is_same_v<T, String>) 
                                { 
                                        result.push_back(&#39;\&#34;&#39;); 
                                        result += arg; 
                                        result.push_back(&#39;\&#34;&#39;); 
                                } 
                                else if constexpr (std::is_same_v<T, Null>) 
                                { 
                                        result += &#34;null&#34;; 
                                } 
                                else if constexpr (std::is_same_v<T, bool>) 
                                { 
                                        result += arg ? &#34;true&#34; : &#34;false&#34;; 
                                } 
                                else if constexpr (std::is_same_v<T, JsonArray>) 
                                { 
                                        if (this->array_type) 
                                        { 
                                                result += &#39;[&#39;; 
                                                for (auto && v : arg) 
                                                { 
                                                        result += v.toString() + &#34;,&#34;; 
                                                } 
                                                result.pop_back(); 
                                                result += &#39;]&#39;; 
                                        } 
                                        else 
                                        { 
                                                result += &#39;{&#39;; 
                                                for (auto && v : arg) 
                                                { 
                                                        result += v.toString() + &#34;,&#34;; 
                                                } 
                                                result.pop_back(); 
                                                result += &#39;}&#39;; 
                                        } 
                                } 
                        }, __value); 
                return result; 
        } 
}; 
 Json节点定义 
#pragma once 
#include&#34;JsonValues.h&#34; 
inline std::ostream & operator <<(std::ostream & o, const JsonNode & jn); 
class JsonNode 
{ 
public: 
        friend inline std::ostream & operator <<(std::ostream & o, const JsonNode & jn); 
        explicit JsonNode(const std::string & key) 
                :__key(std::move(key)) {} 
        explicit JsonNode(const std::string & key, const JsonValue&val) 
                :__key(std::move(key)), __value(std::move(val)) {} 
        JsonNode(JsonNode && node) 
                :__key(std::move(node.__key)), __value(std::move(node.__value)){} 
        JsonNode(const JsonNode & node) 
                :__key(node.__key),__value(node.__value){} 
        std::string toString()const 
        { 
                return __key.size() == 0 ? __value.toString() : &#34;\&#34;&#34; + __key + &#34;\&#34;&#34; + &#34; : &#34; + __value.toString(); 
        } 
        bool operator<(const JsonNode & b)const 
        { 
                return this->__key < b.__key; 
        } 
        auto operator [](const std::string & s) 
        { 
                JSONTYPE value_type = __value.getType(); 
                if (!(value_type == JSONTYPE::JSON_TYPE)) 
                        throw std::runtime_error(&#34;wrong [], value type is: &#34; + value_type); 
                // value must be a set 
                auto & json_nodes = std::get<JsonArray>(__value.__value); 
                auto find_ret = json_nodes.find(JsonNode(s)); 
                if (find_ret == json_nodes.end()) 
                        throw std::runtime_error(&#34;worng [] key is: &#34; + s); 
                return *find_ret;// a jsonvalue not a node 
        } 
        std::string & getKey() 
        { 
                return __key; 
        } 
 
private: 
        std::string __key; 
        JsonValue __value; 
}; 
 
inline std::ostream & operator <<(std::ostream & o, const JsonNode & jn) 
{ 
        o << jn.__value.toString(); 
        return o; 
} 
测试一下 
#include&#34;Json.h&#34; 
int main() 
{ 
        /* 
                // a node 
                &#34;a&#34;:[ 
                        &#34;a_sub_num&#34;:1.0, 
                        &#34;a_sub_bool&#34;:false, 
                        &#34;a_sub_null&#34;:null, 
                        &#34;a_sub_string&#34;:&#34;a string&#34;, 
                        &#34;a_sub_array&#34;:[&#34;array_string&#34;,true,{&#34;a_sub_sub_num&#34;:100}] 
                        ] 
        */ 
        JsonNode node(&#34;a&#34;, JsonValue{ 
                JsonArray{ 
                        JsonNode{&#34;a_sub_num&#34;,JsonValue{1.0}} , 
                        JsonNode{&#34;a_sub_bool&#34;,JsonValue{false}}, 
                        JsonNode{&#34;a_sub_null&#34;,JsonValue{std::monostate{}}}, 
                        JsonNode{&#34;a_sub_string&#34;,JsonValue{String(&#34;a string&#34;)}}, 
                        JsonNode{&#34;a_sub_array&#34;, JsonValue{ 
                                JsonArray{ 
                                        JsonNode{&#34;&#34;,JsonValue{1.0}} , 
                                        JsonNode{&#34;&#34;,JsonValue{true}} , 
                                        JsonNode{&#34;&#34;,JsonValue{JsonArray{JsonNode{&#34;array_string&#34;,JsonValue{100.0}}},false}} 
                                },true 
                        }} 
                },false }); 
        // json node: {&#34;key&#34;,value} 
        // json type: JsonNode{&#34;&#34;,JsonValue{JsonArray{node},false}} 
        // json array type: JsonArray{nodes} 
        std::cout << node.toString()<<std::endl; 
        /* 
                // a json 
                { 
                        &#34;title&#34;: &#34;Design Patterns&#34;, 
                        &#34;subtitle&#34;: &#34;Elements of Reusable Object-Oriented Software&#34;, 
                        &#34;author&#34;: [ 
                            &#34;Erich Gamma&#34;, 
                            &#34;Richard Helm&#34;, 
                            &#34;Ralph Johnson&#34;, 
                            &#34;John Vlissides&#34; 
                        ], 
                        &#34;year&#34;: 2009, 
                        &#34;weight&#34;: 1.8, 
                        &#34;hardcover&#34;: true, 
                        &#34;publisher&#34;: { 
                            &#34;Company&#34;: &#34;Pearson Education&#34;, 
                            &#34;Country&#34;: &#34;India&#34;, 
                        }, 
                        &#34;website&#34;: null 
                } 
        */ 
        JsonNode title(&#34;title&#34;, JsonValue{ String(&#34;Design Patterns&#34;) }); 
        JsonNode subtitle(&#34;subtitle&#34;, JsonValue{ String(&#34;Elements of Reusable Object-Oriented Software&#34;) }); 
        JsonNode author(&#34;author&#34;, JsonValue{ 
                        JsonArray{ 
                                JsonNode{&#34;&#34;,JsonValue{String(&#34;Erich Gamma&#34;)}}, 
                                JsonNode{&#34;&#34;,JsonValue{String(&#34;Richard Helm&#34;)}}, 
                                JsonNode{&#34;&#34;,JsonValue{String(&#34;Ralph Johnson&#34;)}}, 
                                JsonNode{&#34;&#34;,JsonValue{String(&#34;John Vlissides&#34;)}} 
                        }, 
                        true 
                } 
        ); 
        JsonNode year(&#34;year&#34;, JsonValue{ 2009.0 }); 
        JsonNode weight(&#34;weight&#34;, JsonValue{ 1.8 }); 
        JsonNode hardcover(&#34;hardcover&#34;, JsonValue{ true }); 
        JsonNode publisher(&#34;publisher&#34;, JsonValue{ 
                        JsonArray{ 
                                JsonNode{&#34;Company&#34;,JsonValue{String(&#34;Pearson Education&#34;)}}, 
                                JsonNode{&#34;Country&#34;,JsonValue{String(&#34;India&#34;)}}, 
                        }, 
                        false 
                } 
        ); 
        JsonNode website(&#34;website&#34;, JsonValue{ std::monostate{} }); 
        Json js; 
        js.addNode(title); 
        js.addNode(subtitle); 
        js.addNode(author); 
        js.addNode(year); 
        js.addNode(weight); 
        js.addNode(hardcover); 
        js.addNode(publisher); 
        js.addNode(website); 
        std::cout << js.toString() << std::endl; 
        try 
        { 
                auto && company_ret = js[&#34;publisher&#34;][&#34;Company&#34;]; 
                std::cout << company_ret << std::endl; 
 
                auto && year_ret = js[&#34;year&#34;]; 
                std::cout << year_ret << std::endl; 
 
                auto && author_ret = js[&#34;author&#34;]; 
                std::cout << author_ret << std::endl; 
 
                auto && error_ret = js[&#34;abc&#34;]; 
        } 
        catch (const std::exception& e) 
        { 
                std::cerr << e.what(); 
                exit(1); 
        } 
        // auto error_ret = sub_ret[&#34;a&#34;]; 
        return 0; 
} 
/* 
output: 
&#34;a&#34; : {&#34;a_sub_array&#34; : [1.000000,true,{&#34;array_string&#34; : 100.000000}],&#34;a_sub_bool&#34; : false,&#34;a_sub_null&#34; : null,&#34;a_sub_num&#34; : 1.000000,&#34;a_sub_string&#34; : &#34;a string&#34;} 
{ 
        &#34;author&#34; : [&#34;Erich Gamma&#34;,&#34;Richard Helm&#34;,&#34;Ralph Johnson&#34;,&#34;John Vlissides&#34;], 
        &#34;hardcover&#34; : true, 
        &#34;publisher&#34; : {&#34;Company&#34; : &#34;Pearson Education&#34;,&#34;Country&#34; : &#34;India&#34;}, 
        &#34;subtitle&#34; : &#34;Elements of Reusable Object-Oriented Software&#34;, 
        &#34;title&#34; : &#34;Design Patterns&#34;, 
        &#34;website&#34; : null, 
        &#34;weight&#34; : 1.800000, 
        &#34;year&#34; : 2009.000000 
} 
 
&#34;Pearson Education&#34; 
2009.000000 
[&#34;Erich Gamma&#34;,&#34;Richard Helm&#34;,&#34;Ralph Johnson&#34;,&#34;John Vlissides&#34;] 
wrong [] key is: abc 
*/ 
可以预计的是解析的时候大概率受苦,可能整个类都要推倒重来。 
<hr/>更一下开局思路来源:铁甲万能狗:第30篇 C++的variant簡化樹形數據結構的構建 |   
 
 
 
 |