设想,在一次的大规模程序中,你和几位搭档合作写代码。
由于所需的代码量无比庞大,你们遇到了一个无法避免的问题——标识符命名高度重合,造成了代码极度混乱。
如果要重新修改标识符的名称,不仅耗时耗力,还会导致代码的可读性降低。
这种情况下,你会怎么解决这个棘手的问题呢?
。。。。。。。。。。(手动暂停,让我们来稍作思考)。。。。。。。。。。
这时候,团队里的大神提议,将每个人的代码中所用到的标识符,都放进各自的一个专属空间里。
例:A、B、C 三人,虽然都用了标识符名称 x,但是放入各自的空间后,就可以用 A 的 x、 B 的 x、 C 的 x 来区分这三个同名不同意义的 x。
经过尝试和实行后,你们发现,问题果然迎刃而解了。
命名空间 = 名字空间 = 名称空间 = namespace
使用方法:
定义命名空间
namespace A {
int x;
float y;
}
使用命名空间
直接使用
// 使用命名空间 A 里的标识符 x 和 y
A::x = 3;
A::y = 2.2;
使用整个命名空间
using namespace A; // 直接声明要使用的命名空间
// 由于已经声明了使用命名空间 A,因此可以直接使用标识符
x = 3;
y = 2.2;
使用部分命名空间
using A::x; // 声明要使用命名空间 A 的 x
x = 3; // 由于提前声明,因此可以直接使用
A::y; // 因为没有声明要用 y,所有要用 A::y
我们最常用的命名空间是 std,因此在一开始学习代码的时候就会用using namespace std。
在命名空间 std 里,有一个十分重要且实用的 C++ 软件库——STL。
std::nameusing namespace std(但是在大型工程中不推荐使用)
容器是包含、放置数据的工具,可以分为:简单容器、序列容器、关联容器。
由两个单独数据组成(可以是同数据类型/不同数据类型)
常用于 map 中,也可以用于函数中两个返回值的传递
代码实现:
template <class T1, class T2> // 基于模板编写
struct pair {
T1 first; // 第一个成员变量
T2 second; // 第二个成员变量
}
使用方法:
#include <utility> // pair 的头文件
#include <string> // string 的头文件
using namespace std;
int main()
{
// 方法1:同时创建+初始化
pair <string, float> p1 ("Karry", 92.1);
// 方法2:创建之后再赋值
pair <string, float> p2;
p2.first = "Brenda";
p2.second = 22.1;
// 方法3:使用函数 make_pair 创建+初始化
// 优势:程序可以自动推导成员变量的类型
auto p3 = make_pair ("Roy", 11.8);
return 0;
}
访问方法:
// 因为 pair 只有两个元素,只需要用 first 和 second 来访问
cout << p1.first << " " << p2.second << endl;
// 输出结果为:Karry 22.1
对 pair 进行大小比较(先比较 first,再比较 second)
template<class T1, class T2>
void compare(T1 a, T2 b) {
if (a > b)
cout << ">" << endl;
else if (a < b)
cout << "<" << endl;
else if (a == b)
cout << "=" << endl;
}
//(1)
pair <string, int> x = make_pair (2, "Alice");
pair <string, int> y = make_pair (2, "Bob");
compare(x,y);
// 输出结果为:<
//(2)
pair <string, int> x = make_pair (2, "Alice");
pair <string, int> y = make_pair (1, "Bob");
compare(x,y);
// 输出结果为:>
//(3)
pair <string, int> x = make_pair (2, "Bob");
pair <string, int> y = make_pair (2, "Bob");
compare(x,y);
// 输出结果为:=
和 pair 类似,但是可以由 n 个数据组成
适用于有多个返回值的函数的返回值传递
使用方法:
#include <tuple> // tuple 的头文件
#include <string> // string 的头文件
using namespace std;
int main()
{
// 方法1:同时创建+初始化(需要多少个数据就写多少个)
tuple <string, int, float> p1 ("Karry", 23, 92.1);
// 方法2:使用函数 make_tuple 创建+初始化
auto p2 = make_tuple ("Brenda", 20, 22.1);
// 方法3:结合函数 tie 和 make_tuple 进行赋值创建
// 没有一个特定的 tuple 标识符,但是可以同时对个别数据进行操作
string name;
int age;
float marks;
tie (name, age, marks) = make_tuple ("Roy", 22, 11.8);
return 0;
}
访问方法:
// 使用 get 函数,通过下标访问
// 下标需要在编译时确定,只能使用确定的数字,不能使用变量,否则会编译错误
auto x = get <0> (p1); // p1[0] = "Karry"
auto y = get <1> (p2); // p2[1] = 20
auto z = get <2> (p3); // p3[2] = 11.8
cout << x << " " << y << " " << z << endl;
// 输出结果为:Karry 20 11.8
对 tuple 进行大小比较的方式和 pair 类似 [点击跳转]
返回值类型为 tuple 时:
tuple <int, float> calc(int n) {
return make_tuple(n + 2, n / 2.0);
}
// 方法1:用 tuple 来接收函数返回值
tuple <int, float> a;
a = calc(3);
cout << get<0>(a) << " " << get<1>(a) << endl;
// 方法2:用 tie 函数来接收函数返回值
// 优势:可以直接分开使用函数返回值
int num;
float data;
tie(num, data) = calc(3);
cout << num << " " << data << endl;
// 输出结果皆为:5 1.5
例子:array、vector、deque、list、forward list
特点概览:
| 长度 | 添加元素 | 删除元素 | 访问元素 | |
|---|---|---|---|---|
| array | 固定 | 可以在任意位置 | 可以在任意位置 | 通过下标 |
| vector | 不固定 | 一般在尾部 | 一般在尾部 | 通过下标 |
| deque | 不固定 | 在头部、尾部 | 在头部、尾部 | 通过下标 |
| list | 不固定 | 可以在任意位置 | 可以在任意位置 | 双向 |
| forward list | 不固定 | 可以在任意位置 | 可以在任意位置 | 只可以正向 |
可以自动扩展容量的动态数组
使用方法:
#include <vector> // vector 的头文件
using namespace std;
// 创建:vector <容器中的数据类型> 容器名称;
vector <int> vec;
常用函数:
vec.size(); // 返回 vector vec 中的元素数量
vec.clear(); // 清空数组
vec.push_back(1); // 把 1 添加进 vector vec
vec.pop_back(); // 把最后一个元素删除
vec.insert(vec.begin() + ind, 5); // 在下标为 ind 的位置添加元素 5,其余元素往后挪
vec.erase(vec.begin() + ind); // 把下标为 ind 的数据删除
遍历方法:
// 方法1:使用下标
for (int ind = 0; ind < vec.size(); ++ind) {
cout << vec[ind] << " ";
}
// 方法2:按照范围
for (auto &x : vec) {
cout << x << " ";
}
// 方法3:使用迭代器
// 为了方便,也可以使用 auto it;
vector <int>::iterator it;
for (it = vec.begin(); it != vec.end(); ++it) {
cout << *it << " ";
}
双向链表容器
list 中的元素可以分散存储在内存空间
优势:在任意位置插入和删除元素的时间复杂度 = O(1),效率高,且迭代器不会失效
缺点:无法使用下标访问元素,只能遍历寻找
使用方法:
#include <list> // list 的头文件
using namespace std;
// 创建:list <存储的数据类型> 标识符名称;
list <int> num;
常用函数:
num.push_front(1); // 在头部插入元素 1
num.push_back(1); // 在尾部添加元素 1
num.pop_front(); // 删除第一个元素
num.pop_back(); // 删除最后一个元素
num.insert(iter, 1); // 在 iter 指向的位置添加元素 1
num.erase(iter); // 删除 iter 指向的位置的元素
find(num.begin(), num.end(), 1); // 返回元素 1 所在位置的迭代器
set 是包含不重复元素的无序集合
无序,指的是 set 内的元素不按照 “插入顺序” 进行排列
内部的元素根据大小顺序进行排列
使用方法:
#include <set> // map 的头文件
using namespace std;
set <int> s;
常用函数:
s.insert(val); // 插入元素 val(不可以插入重复的元素)
s.find(val); // 返回 val 所在位置的迭代器
s.erase(s.find(val)); // 由于 set 无序且无法用下标访问,需要遍历寻找再进行删除
s.count(val); // 统计 set 内有多少元素 val
// 由于不允许出现重复性的元素,因此返回值只有 0 和 1
将一个数据映射到另一个数据,每个元素都是一个 pair <Key, T>
map 中的每个 Key 不允许出现重复
可以通过下标访问,访问时如果元素不存在,则会创建一个
使用方法:
#include <map> // map 的头文件
#include <string> // string 的头文件
using namespace std;
int main()
{
map <string, int> m;
// 添加的方法1
// 为 map 中添加 make_pair("Karry", 921)
m["Karry"] = 921;
// 添加的方法2
m.insert(make_pair("Brenda", 221));
return 0;
}
常用函数:
m.find(key); // 返回指向 key 的迭代器
m.count(key); // 返回 map 内 key 的数量
// 由于不允许出现重复元素,因此返回值只有 0 或 1
m.erase(m.find(key)); // 删除元素 key
迭代器(iterator)类似指针,是一种用来遍历元素的数据类型
优势:不需要暴露访问对象的内部表示就可以顺序访问对象的元素
以 vector 为例的使用方法:
// 定义迭代器
// 迭代器 iter 指向 int 类型的 vector
vector <int>::iterator iter;
x.begin(); // 返回 vector x 中第一个元素的迭代器
x.end(); // 返回 vector x 中最后一个元素之后的位置的迭代器
// begin 和 end 形成了左闭右开的区间
++iter // 下一个位置的迭代器
--iter // 上一个位置的迭代器
iter += n // 从 iter 位置开始算,后面第 n 个位置的迭代器
iter -= n // 从 iter 位置开始算,前面第 n 个位置的迭代器
*iter // 解引用运算符,返回左值引用,返回 iter 指向的位置的数据
用迭代器来遍历容器的方法可参考 vector 处的遍历方法
迭代器失效 = 迭代器不再指向原本应指向的元素
以 vector 为例,导致迭代器失效的情况:
添加元素
使用 insert 插入元素
在特定位置添加元素,其余的元素会向后挪,由于原先内存空间存储的元素改变,因此受影响的迭代器失效。
使用 push_back 插入元素
当 size 达到 capacity 时,vector 会额外申请一个 2*capacity 的内存空间,并将原有的数据移到新内存空间,因此所有的迭代器均失效。
删除元素
使用 erase 删除元素
删除特定位置的元素后,其余位置会向前挪,原先的内存空间存储的元素改变,受影响的迭代器失效。例:
vector <int> vec = {1, 2, 3, 4, 5}; auto first = vec.begin(); // first 指向 1 auto second = vec.begin() + 1; // second 指向 2 auto third = vec.begin() + 2; // third 指向 3 auto itr = vec.erase(second); // 删除了迭代器 second 指向的元素,vec = {1, 3, 4, 5} // first 指向 1,没有改变 // second 和 third 失效 // itr 指向第二个位置的新元素 3
迭代器的失效和容器的数据结构有关,绝对安全的准则是:修改了容器内容后,不使用先前的迭代器
我正在使用puppet为ruby程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这
我正在使用Mandrill的RubyAPIGem并使用以下简单的测试模板:testastic按照Heroku指南中的示例,我有以下Ruby代码:require'mandrill'm=Mandrill::API.newrendered=m.templates.render'test-template',[{:header=>'someheadertext',:main_section=>'Themaincontentblock',:footer=>'asdf'}]mail(:to=>"JaysonLane",:subject=>"TestEmail")do|format|format.h
所以这可能有点令人困惑,但请耐心等待。简而言之,我想遍历具有特定键值的所有属性,然后如果值不为空,则将它们插入到模板中。这是我的代码:属性:#===DefaultfileConfigurations#default['elasticsearch']['default']['ES_USER']=''default['elasticsearch']['default']['ES_GROUP']=''default['elasticsearch']['default']['ES_HEAP_SIZE']=''default['elasticsearch']['default']['MAX_OP
一般来说,我是Middleman和ruby的新手。我已经安装了Ruby我已经安装了Middleman和gem以使其运行。我需要使用slim而不是默认的模板系统。所以我安装了Slimgem。Slim的网站只说我需要'slim'才能让它工作。中间人网站说我只需要在config.rb文件中添加模板引擎,但是没有给出例子...对于没有ruby背景的人来说,这没有帮助。我在git上找了几个config.rb,它们都有:require'slim'和#Setslim-langoutputstyleSlim::Engine.set_default_options:pretty=>true#Se
我有一个偏爱:如何将像o.office这样的值插入到属性中?value="#{o.office}"无效。 最佳答案 'type='text'/>或者你可以使用表单助手 关于ruby-on-rails-如何将变量值插入ERB模板中的HTML标签?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/6172174/
有没有办法在liquidtemplate中输出(用于调试/信息目的)可用对象和对象属性??也就是说,假设我正在使用jekyll站点生成工具,并且我在我的index.html模板中(据我所知,这是一个液体模板)。它可能看起来像这样{%forpostinsite.posts%}{{post.date|date_to_string}}»{{post.title}}{%endfor%}是否有任何我可以使用的模板标签会告诉我/输出名为post的变量在此模板(以及其他模板)中可用。此外,是否有任何模板标签可以告诉我post对象具有键date、title、url、摘录、永久链接等
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visitthehelpcenter.关闭11年前。哪些模板引擎/模板语言是图灵完备的?到目前为止,我听说过这些:FreeMarker(用java实现)MovableTypes模板语言(perl)xslt:-(Cheetah(Python语言)聪明(PHP)还有其他的(特别是用perl实现的)吗?Ps:不要浪费时间向我解释MVC,以及为什么图灵完整模板不好,以及为什么这不是一个有用的比较点:)
我知道我可以用这段代码迭代liquid模板中的数组:{%foriteminmyarray%}{{item.label}}但是我怎样才能得到我的项目在数组中的索引呢? 最佳答案 根据"LiquidforDesigners"liquid的github部分...forloop.length#=>lengthoftheentireforloopforloop.index#=>indexofthecurrentiterationforloop.index0#=>indexofthecurrentiteration(zerobased)forl
究竟如何使用Liquid中的map过滤器?我在Jekyll中使用它。---my_array:[apple,banana,orage]my_map:hello:worldfoo:barmy_string:"howdoesthiswork?"---{{page.my_map|map...}}这就是我迷路的地方。我似乎无法在文档或任何其他在线网站上找到任何关于它的用法示例。顺便说一下,我还不懂Ruby,所以sourcecode我也不清楚。来自filtertests看起来下面应该产生一些东西,但在GitHub上,我什么也没得到:{{site.posts|map:'title'|array_to
我有一些nginx站点的资源和提供程序,它可以为站点写出配置文件。action:startdotemplate"/etc/nginx/sites-enabled/my_site"dosource"nginx_site.conf.erb"notifies:reload,"service[nginx]"endend当我从另一本Recipe中使用它时,找不到模板nginx_site.conf.erb,因为Chef正在寻找调用此资源的模板。有没有办法告诉Chef在nginx资源和提供者Recipe中寻找模板? 最佳答案 您可以为templa