详解c++---string的介绍(上)

news2024/11/23 23:43:54

这里写目录标题

  • 什么是string
  • string的构造函数
  • string的赋值重载
  • string的遍历
    • 第一种方式 [ ]
    • 第二种方式 范围for
    • 第三种方式 正向迭代器
    • 反向迭代器
  • string中的capacity
    • size length
    • max_size
    • capacity
    • reserve
    • resize
    • shrink_to_fit
  • string的element access

什么是string

那这里大家就只用记住这么几点就够了,首先string他是一个类,这个类他是定义在string这个文件里面的,并且我们还用了std这个命名空间将他围了起来以免发生命名冲突,所以在下面的代码中我们首先要干的事情就是包含sting这个头文件,然后在用using namespace来释放std这个命名空间,那么这里我们的代码就如下:

#include<string>
using namespace std;

其次我们要知道的就是string这个类他是专门用来处理字符串的,在这个类里面有这么几个成员变量:

#include<iostream>
class basic_string
{
public:

private:
	char* _str;
	size_t _size;
	size_t _capacity;
};

其中_str就是一个指针,这个指针指向的就是我们的字符串,其次这里的_size就是用来表示这里字符串的有效长度(就是不包括\0),最后这里的_capacity表示的意思就是容量,也就是当前能够存储有效字符的个数,比如_capacity=20的意思就是此时最多能够储存20个有效字符,当然!当_size等于_capacity的时候,他就会自动进行扩容使其能够容纳下更多的字符,那么这就是这三个成员变量的意义,其次还有一件事就是在文件里面我们还对这个类实现了一个模板其代码的形式是这个样子:

template<class T>
class basic_string
{
public:

private:
	T* _str;
	size_t _size;
	size_t _capacity;
};

那这里之所以实现一个模板的原因是因为:在不同的环境下我们的字符有着不同的类型,比如说:utf-8,utf-16,utf-32,w_char等等不同的类型,而这些不同的类型他们所占的空间以及对应的规则是不一样的,而我们平时使用最多的是utf-8这个类型,这个类型的字符占8个比特位而且他还能兼容ascall,所以他在内存消耗方面和使用范围方面都占了很大的优势,所以我们平时使用最多的就是utf-8这个类型,但是其他的类型不代表从今往后我们都不使用了,所以为了处理这些不同类型的字符,这个库的作者就采用了模板的形式来解决这个问题,并且对这个模板所创建出来的类型进行typedef重命名,以此来简化他的名字长度,那么我们平时所用的string就是对应的utf-8这个类型的字符他就是由typedef class basic_string<char> string重命名得来的,然后对于utf-16这个类型的字符我们就得使用u16string来对其进行处理,对于utf-32这个类型的字符我们就得使用u32string来对其进行处理等等,那么知道了这些我们就可以来跟大家介绍如何使用这里的string来对字符串进行操作。

string的构造函数

一个类中必定少不了构造函数,就算你不写编译器也会自动的给你补上一个,那么对于string这个类,开发者们给了我们多个构造函数来方便我们的日常使用:
在这里插入图片描述
第一个:

string();

大家可以看到第一个构造函数中是没有参数的,那么这个用这个构造函数来对其进行初始化的话,我们实例化出来的对象中是不会储存任何的有效字符的,比如说我们下面的代码:

void test1()
{
	string s1;
	cout << s1.size() << endl;//获取该对象中size的值
	cout << s1.capacity() << endl;//获取该对象中capacity的值
}

运行结果如下:
在这里插入图片描述
这里大家就可以看到该对象中的字符串有效长度为0,但是他的容量却不为0,那么这就是第一个构造函数所带来的结果。那么这里大姐可以看看官方给的英文解释:
在这里插入图片描述

第二个:

string (const string& str);

大家根据这里的参数类型就不难看出第二种形式是一个拷贝构造函数,经过前面的学习想必大家对拷贝构造函数已经非常的熟悉,我们就直接通过下面的代码来大家看看这里的使用结果是如何:

void test1()
{
	string s1;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	string s2("abcdefg");//第四种初始化方式
	string s3(s2);
	cout << s3.c_str() << endl;//打印这个对象指向的字符串的内容
	cout << s3.size() << endl;
	cout << s3.capacity() << endl;
}

其代码的运行结果如下:
在这里插入图片描述
我们可以看到这里s3的中的字符串的内容和s2中字符串的内容是一样的,那么这就是第二种构造函数初始化的结果。下面是官方对这个初始化方式的介绍:
在这里插入图片描述

第三种:

string (const string& str, size_t pos, size_t len = npos);

第三种初始化的方式就是在第二种的基础上做出了一点改变,我们可以通过后面两个参数来控制我们想要拷贝的内容,第二个参数pos表示的是复制的开始,第三个参数参数表示的是你想要复制的长度,我们可以通过下面的代码来理解一下:

void test1()
{
	string s1;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	string s2("abcdefg");//第四种初始化方式
	cout << "第二种构造函数的结果为:" << endl;
	string s3(s2);
	cout << s3.c_str() << endl;//打印这个对象指向的字符串的内容
	cout << s3.size() << endl;
	cout << s3.capacity() << endl;
	cout << "第三种构造函数的结果为:" << endl;
	string s4(s2,1,3);
	cout << s4.c_str() << endl;//打印这个对象指向的字符串的内容
	cout << s4.size() << endl;
	cout << s4.capacity() << endl;
}

这段代码的运行结果为:
在这里插入图片描述
首先s2的内容是abcdefg,然后我们在用第三种构造函数进行初始化的时候给的起始位置是1,那这里对应的就是第二个元素d,给的长度是3,那么这里表示的意思就是从第二个元素开始往后数三个元素,将这三个元素来对s4进行初始化,所以这里s4的内容就是bcd,最后这里有两个小点需要大家注意一下
第一点:给的起始位置一定要合法,如果不合法的话就会报错,比如说我们下面的代码:

void test2()
{
	string s1("abcdefg");
	string s2(s1, 100, 2);
}

那么我们将这个代码运行一下就可以看到编译器报错了:
在这里插入图片描述
报错的原因就是因为:我们这里给的起始位置不合法,s1初始化的内容是abcdefg\0所以s1中一共有8个元素,所以当我们用第三种方式进行初始化的时候,我们给的起始位置就只能是0到7,而我们上面的代码给的却是100,那毫无疑问肯定是错的,所以就报错了。
第二点:该构造函数的第三个参数表示的意思是想要拷贝过来的字符串的长度,所以这里肯定就会出现一个问题就是,如果我们给的长度非常的大超出了从起始位置开始剩余的字符串长度,那会出现什么情况呢?那这里我们就可以看看下面的代码:

void test2()
{
	string s1("abcdefg");
	string s2(s1, 2, 100);
	cout << s2.c_str() << endl;
}
int main()
{
	test2();
	return 0;
}

该代码的运行结果如下:
在这里插入图片描述
那这里我们就发现,如果给的长度过长的话,那编译器在执行拷贝构造的时候也只会拷贝到字符串的结尾为止,并不会报错或者多拷贝的情况,那么这里细心的小伙伴们肯定可以观察到第三个参数我们是给了缺省值的,而这个缺省值的大小是npos也就是-1,而第三个参数的类型是无符号整型,所以这里的-1并不表示数学上的-1,而是一个非常大的正整数,那么以后大家在使用这个函数的时候就可以利用这个缺省值来方便使用这个函数,如果你想从某个位置开始将后面的所有元素都进行拷贝的话,我们就可以不对第三个参数进行传参直接利用其缺省值,这样我们就可以不用数这里的长度,从而提升我们写代码的效率,那么下面就是官方对这个函数的英语介绍,大家可以看看:
在这里插入图片描述
第四个:

string (const char* s);

这个构造函数的参数是一个字符指针,那么他表示的意思就是可以使用一个字符串常量来对其进行初始化,比如说我们下面的代码:

	cout << "第四种构造函数的结果为:" << endl;
	string s5("abcdefg");
	cout << s5.c_str() << endl;//打印这个对象指向的字符串的内容
	cout << s5.size() << endl;
	cout << s5.capacity() << endl;

该代码的运行结果如下:
在这里插入图片描述
其次我们这个构造函数他没有用explicit进行修饰,所以我们还可以利用隐式类型转换通过等于号来进行赋值,比如说下面的代码:

	cout << "第四种构造函数的结果为:" << endl;
	string s5 = "abcdefg";
	cout << s5.c_str() << endl;//打印这个对象指向的字符串的内容
	cout << s5.size() << endl;
	cout << s5.capacity() << endl;

那么运行的结果也是一模一样的:
在这里插入图片描述
那么这就是第四种初始化的方法,大家可以看看官方对他的英文介绍:
在这里插入图片描述
第五种:

string (const char* s, size_t n);

这种初始化方式和第四种差不多,最大的区别就是多了一个参数n,那么这个n表示的意思就是拷贝该字符串的前几个字符,比如说下面的代码:

	cout << "第四种构造函数的结果为:" << endl;
	string s5 = "abcdefg";
	cout << s5.c_str() << endl;//打印这个对象指向的字符串的内容
	cout << s5.size() << endl;
	cout << s5.capacity() << endl;
	cout << "第五种构造函数的结果为:" << endl;
	string s6 ("abcdefg",3);
	cout << s6.c_str() << endl;//打印这个对象指向的字符串的内容
	cout << s6.size() << endl;
	cout << s6.capacity() << endl;

该代码的运行结果为:
在这里插入图片描述
那这里我们传给n的值是3,所以他就会拷贝该字符串的前3个字符也就是这里的abc,那么这里他也会遇到同样的一个问题就是,当我们给这里n的值大于字符串的长度时编译器会报错吗?答案是不会的,这里的处理方式和上面是一样的,他会直接拷贝到字符串结束而不会报错,那这就是第五种拷贝构造函数,其官方给的英语解释如下:
在这里插入图片描述
第六种:

string (size_t n, char c);

这个构造函数的意思就是用多少个字符来对其进行初始化,第一个参数n表示的就是字符的个数,第二个参数c表示的就是字符,比如说我们想用10个字符’ * '来进行初始化,那我们的代码就是这样的:

	cout << "第六种构造函数的结果为:" << endl;
	string s7(10, '*');
	cout << s7.c_str() << endl;//打印这个对象指向的字符串的内容
	cout << s7.size() << endl;
	cout << s7.capacity() << endl;

其运行的结果就如下:

在这里插入图片描述
该函数的官方介绍如下图所示:
在这里插入图片描述
第七种:

template <class InputIterator>
string  (InputIterator first, InputIterator last);

那么这种方式就是用迭代器来进行初始化,那这里大家就看个例子就行,具体是什么意思大家得学了下面的内容就可以理解:

	cout << "第六种构造函数的结果为:" << endl;
	string s7(10, '*');
	cout << s7.c_str() << endl;//打印这个对象指向的字符串的内容
	cout << s7.size() << endl;
	cout << s7.capacity() << endl;
	cout << "第七种构造函数的结果为:" << endl;
	string s8(s7.begin(), s7.end());
	cout << s8.c_str() << endl;

这段代码的运行结果为:
在这里插入图片描述
该函数的官方英文解释如下:
在这里插入图片描述

string的赋值重载

在该库当中实现了三种类型的赋值重载:
在这里插入图片描述
分别是用一个string类型的对象来完成赋值重载,用一个字符串来完成赋值重载,用一个字符来完成赋值重载,那这里的代码样例就如下:

void test3()
{
	string s1("abcdefg");
	string s2, s3, s4;
	s2 = s1;
	s3 = "hijklmn";
	s4 = 'h';
	cout << s2.c_str() << endl;
	cout << s3.c_str() << endl;
	cout << s4.c_str() << endl;
}

这段代码的运行结果就如下:
在这里插入图片描述

string的遍历

既然我们能对string所创建的对象进行初始化赋予他内容的话,那么接下来我们要做的就是遍历这个对象中的数据,那么这里我们有三种方式来进行遍历。

第一种方式 [ ]

第一种遍历的方式就是通过下标引用操作符( [ ] )来实现遍历,在库中实现了对该操作符的重载,这样就能够让我们直接访问并修改这个对象中的数据,比如说下面的代码:

void test4()
{
	string s1("abcdefg");
	int i = 0;
	while (i < s1.size())
	{
		s1[i++]++;
	}
	cout << s1.c_str() << endl;
}

这段代码运行的结果为:
在这里插入图片描述
那么这里大家可以看到原来的abcdefg变成了bcdefgh,而英语字母的ascll码值是连续的,所以我们这里的执行结果就是正确的,那么这里大家应该能够理解这里[ 的]作用,他可以让我们以下标的方式来访问到string对象中的数据,并且还能对其进行修改,而且库中还提供了两个不同的版本:
在这里插入图片描述
一个是const版本另外一个是非const版本,那const版本就只能读不能写,而非const版本是既可以读还可以写,下面是官方对这个操作符重载的介绍:
在这里插入图片描述
在这里插入图片描述

第二种方式 范围for

第二种遍历的方式就是通过范围for来实现string的遍历,那这里我们跟上面一样对内容进行修改使其每个元素的ascall值都加一,那这样的话我们就得在auto后面加上一个&将其形式变成引用这样得话,我们就可以直接对其内容进行修改,那么这里我们的代码就如下:

void test4()
{
	string s1("abcdefg");
	int i = 0;
	while (i < s1.size())
	{
		s1[i++]++;
	}
	cout << s1.c_str() << endl;
	for (auto& ch : s1)
	{
		ch++;
	}
	cout << s1.c_str() << endl;
}

代码得运行结果如下:
在这里插入图片描述
字符串由bcdefgh变成了cdefghi,每个元素得ascll值都加上了1,那么这就说明我们得代码是真确的。

第三种方式 正向迭代器

第三种方式是通过正向迭代器来实现对字符串的遍历,我们首先看看迭代器在库中的形势:
在这里插入图片描述
首先迭代器的一个关键是iterator ,这是一个类型这个类型属于string这个类,然后我们用这个类型创建变量的时候就得用上面的这些函数来进行初始化,比如说我们下面这行代码:

string::iterator it1 = s1.begin();

那这里我们就来看看上面的这两个函数是什么意思,首先来看看begin:
在这里插入图片描述
begin这个函数的作用就是让迭代器指向字符串的第一个元素,那么同样的道理end函数的作用就应该是让迭代器指向字符串的末尾也就是\0,那么该函数的介绍如下:
在这里插入图片描述
我们说迭代器行为上像指针,所以在使用的时候我们就以指针的形式来使用他,比如说下面的代码:

void test4()
{
	string s1("abcdefg");
	int i = 0;
	while (i < s1.size())
	{
		s1[i++]++;
	}
	cout << s1.c_str() << endl;
	for (auto& ch : s1)
	{
		ch++;
	}
	cout << s1.c_str() << endl;
	string::iterator it1 = s1.begin();
	while (it1 != s1.end())
	{
		(*it1)++;
		it1++;
	}
	cout << s1.c_str() << endl;
}

这段代码的运行结果如下:
在这里插入图片描述
字符串cdefghi变成了defghij,所以我们这里的代码实现的就是正确的,那这里肯定有很多小伙伴们有疑问说:为什么得搞一个迭代器呢?我们前面的两种方式用的不是挺好的吗?那这里大家要知道的是迭代器遍历数据是一个通用的形式,对于string这个类可以使用对于我们后面学的其他库他也可以使用,而前两种遍历方式他对于现在string这个库可以很好的遍历并修改,但是对于其他的库他就不会那么容易了,有可能就完全遍历不了,所以这就是我们学习迭代器的原因,这里还有一点大家要注意的就是,迭代他是行为上类似于指针,那有些小伙伴就会认为他就是指针,既然是指针的话那他就会直接将上面的代码修改成这样:

	char* it1 = s1.begin();
	while (it1 != s1.end())
	{
		(*it1)++;
		it1++;
	}
	cout << s1.c_str() << endl;

那这里就是一个非常严重的错误,因为我们学的stl他只是一个规范,并没有准确的规定其实现的原理,也就是说不同的平台下实现的原理是不一样,那在有些平台下他会通过指针来实现这个迭代器,而有些平台却不会,那这里我们拿char*来进行接收的话就可能会导致该代码在一些平台上跑的了,在另外的一些平台跑不了的情况,这里大家要注意一下。

反向迭代器

既然有正向迭代器,那么也就一定有反向迭代器,反向迭代器就得将iterator改成了reverse_iterator,将begin改成rbegin,将end改成rend,但是跳转数据的++可不能改成–,下面是rbegin的函数介绍:
在这里插入图片描述

rend的函数介绍:

在这里插入图片描述

这里大家可以看看下面的代码来看看反向迭代器是如何使用的:

void test5()
{
	string s1("abcdefg");
	string::reverse_iterator it1 = s1.rbegin();
	while (it1 != s1.rend())
	{
		cout << *it1;
		it1++;
	}
}

代码的运行结果如下:
在这里插入图片描述
正向迭代器是从左向右遍历数据,那我们这里的反向迭代器就是从右向左的遍历数据,所以我们这里打印出来的数据就是gfedcba,那这里打击要注意的一点就是rend和end不能混着使用,比如说在while循环中的判断语句就不能写成这样:

	string s1("abcdefg");
	string::reverse_iterator it1 = s1.rbegin();
	while (it1 != s1.end())

因为it1的类型是reverse_iterator类型,而end返回的类型是iterator类型,这两个类型是不一样的,所以就不能一起进行比较,这里大家要注意一下。最后再说一点就是我们这里使用的end rend,begin rbegin都有两个类型一个是const,另外一个是非const,那下面的这四个函数就与上面的4个函数一一对应只不过他们只用一个类型就是const:
在这里插入图片描述
所以他们也就叫cbegin,cend,crbegin,crend,这里大家可以看看下面的函数介绍:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

string中的capacity

我们来看看这一块有哪些函数
在这里插入图片描述

size length

这两个函数size和length的作用是一样的,都是返回对象中的字符串的长度:

void test6()
{
	string s1("abcdefg");
	cout << s1.size() << endl;
	cout << s1.length() << endl;
}

在这里插入图片描述
这里初始化的内容是abcdefg有7个有效字符,所以这里打印出来的字符串长度就是7。这里的用法都非常的简单哈,大家可以来看看官方给的英文介绍;
在这里插入图片描述
在这里插入图片描述

max_size

这个函数用的就很少,他的功能就是告诉使用者使用string创建的对象最多能够容纳多少个有效字符。

void test6()
{
	string s1("abcdefg");
	cout << s1.size() << endl;
	cout << s1.length() << endl;
	string s2("abcd");
	cout << s1.max_size() << endl;
	cout << s2.max_size() << endl;
}

这段代码的运行结果为:
在这里插入图片描述
那么这里大家可以看到这里我们初始化的长度不一样,但是他们所能够达到的最大长度都是一样的是一个非常大的数。
在这里插入图片描述

capacity

这个函数的作用就是告诉使用者当前对象的容量是多少,比如说下面的代码:

	string s1("abcdefg");
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;

在这里插入图片描述
那么这就表明当前对象中含有7个有效字符容量为15,当size的值大于capacity的值时,该对象就会自动的扩容增加capacity的值,比如说我们下面的代码:

	string s2;
	int i = 0;
	size_t _capacity = s2.capacity();
	while (i < 1000)
	{
		s2 += 'a';//向字符串尾插一个字符
		if (s2.capacity() != _capacity)//如果容量发生了改变就打印改变后的值
		{
			cout << _capacity << endl;
			_capacity = s2.capacity();
		}
		i++;
	}
	cout << _capacity << endl;

其代码的运行结果如下:
在这里插入图片描述
我们可以看到这里随着字符串的长度不断地变长,该对象的容量也在不断地变大,其变大的规律为每次扩大1.5倍,当然这里扩大的规律不同的编译器下是不一样的,gcc编译器就是每次都扩容两倍,那么这就是capacity函数的用法,他的英文解释如下:在这里插入图片描述

reserve

大家可以看到,当我们不断地往对象中插入数据时,对象就会自动的进行扩容,那这里就会存在一个问题:扩容是会损失效率的,如果扩容的次数过多的话就会导致代码的执行效率降低,所以当我们知道了要操作的字符串的长度时,我们最好能够一次性将容量开够以免进行多次扩容,那这里我们要用的函数就是reserve,他可以一次性开辟一个我们想要的空间的大小,比如说下面的代码:

	string s1;
	s1.reserve(1000);
	cout << s1.capacity() << endl;

这段代码的运行结果为:
在这里插入图片描述
我们给reserve函数传的参数是1000,表明的意思是想将容量开到1000,但是打印出来的capacity的值却变成了1007,那这就是因为在扩容的过程中存在着内存对齐的行为,所以编译器会多开一点空间,那么这就是该函数的作用,大家可以看看对应的英文介绍:
在这里插入图片描述

resize

这个函数的作用就是修改有效字符的长度,比如说下面的代码:

	string s1("abcdefg");
	string s2("abcdefg");
	string s3("abcdefg");
	cout << s1.size() << endl;
	cout << s2.size() << endl;
	cout << s3.size() << endl;
	cout << s1.capacity() << endl;
	cout << s2.capacity() << endl;
	cout << s3.capacity() << endl;
	s1.resize(4);
	s2.resize(10,'*');
	s3.resize(19,'#');
	cout << s1.c_str() << endl;
	cout << s2.c_str() << endl;
	cout << s3.c_str() << endl;
	cout << s1.size() << endl;
	cout << s2.size() << endl;
	cout << s3.size() << endl;
	cout << s1.capacity() << endl;
	cout << s2.capacity() << endl;
	cout << s3.capacity() << endl;

如果你给的长度小于原来字符串的长度的话,那么经过resize操作你的字符串将变的更小,如果你给的长度大于字符串的长度但是小于容量的值的话,那么该字符串的长度将边长并且读出来的地方将由你给的字符来填充,当你给的长度大于字符串的长度还大于容量的话,那么编译器将自动的扩容并且将多余的长度用你给的第二个字符来进行填充,当然这里你可以不使用第二个参数,这样的话编译器就会拿\0来进行填充,上面的代码运行结果如下:
在这里插入图片描述

这里大家可以看到这三个对象的长度都发生了变化,s1的长度变小,s2 s3的长度变大,而s1 s2的容量没有变但是s3的容量却变大了,那么这就是resize的作用他可以改变有效字符的长度,并且还能按我们给的字符来对多余的长度进行填充,下面就是该函数的英文解释:
在这里插入图片描述

shrink_to_fit

这个函数的作用就是将对象中容量的大小与size的大小保持一致,比如说下面的代码:

#include <iostream>
#include <string>

int main ()
{
  std::string str (100,'x');
  std::cout << "1. capacity of str: " << str.capacity() << '\n';

  str.resize(10);
  std::cout << "2. capacity of str: " << str.capacity() << '\n';

  str.shrink_to_fit();
  std::cout << "3. capacity of str: " << str.capacity() << '\n';

  return 0;
}

这个代码的运行结果如下:
在这里插入图片描述
这里我们用resize函数将对象的有效长度降为10之后,再用shrink_to_fit就会使得capacity的值和size的值保持一致都变成了 10,当然这段代码的运行结果我是抄官网的,我的vs编译器执行的结果与官网的不一样,他只能做到尽量保持一致,那么这里大家了解一下就行这个在实际使用中用到的地方很少。
在这里插入图片描述

string的element access

在这里插入图片描述
这里at的功能和上面的[ ]的功能是一样的,都是访问对象中字符串的元素,但是区别就在于对于不合法的位置[ ]会直接报错而at他会抛异常,比如说我们下面的代码:

void test7()
{
	string s1("abcdefg");
	s1[100]++;
}

我们将这段代码运行起来就可以发现编译器直接报错了:
在这里插入图片描述
我们再看这段代码:

void test7()
{
	string s1("abcdefg");
	//s1[100]++;
	s1.at(100) = 'd';
	
}
int main()
{
	try
	{
		test7();
	}
	catch (exception& e)
	{
		cout << e.what() << endl;
	}
	return 0;
}

将这段代码运行一下就可以发现,他并没有直接报出错误,而是抛出了异常:
在这里插入图片描述
说这是一个不正常的字符位置,那么这就是at和[ ]的区别,大家这里注意一下就行,在平时使用过程中我们还是用[ ]用的多一些,然后在这个模块当中还有back和front这两个函数,这两个函数的作用就分别是返回字符串中的最后一个元素和返回字符串中的第一个元素,这里的返回是引用返回,所以我们就可以通过该函数来直接修改字符串中的内容,比如说下面的代码:

	string s1("abcdefg");
	s1.front() = 'g';
	s1.back() = 'a';
	cout << s1.c_str() << endl;

该代码的运行结果为:
在这里插入图片描述
该对象中的字符串确实发生了修改那么这就说明我们的代码实现的是正确的这四个函数的英文介绍如下图所示:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/89821.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

k8s编程operator实战之云编码平台——③Code-Server Pod访问实现

文章目录1、openresty介绍和安装2、实现code-server的反向代理3、动态反向代理实现启动多个code-server访问k8s编程operator系列&#xff1a;k8s编程operator——(1) client-go基础部分k8s编程operator——(2) client-go中的informerk8s编程operator——(3) 自定义资源CRDk8s编…

【提高代码可读性】—— 手握多个代码优化技巧、细数哪些惊艳一时的策略

回顾 前期 趁着下班前五分钟书写——Vue3通讯(常规写法、语法糖、v-modle、兄弟通讯)_0.活在风浪里的博客-CSDN博客Vue3 组件通讯https://blog.csdn.net/m0_57904695/article/details/128145150?spm1001.2014.3001.5501 目录 一、可选链接运算符【&#xff1f;.】 二、空…

AD20和立创EDA设计(2)提取立创EDA的原理图库和PCB库

&#xff08;1&#xff09;因为AD20需要自己画原理图库和PCB库。所以我建议新手先用立创EDA画好原理图&#xff0c;转换为PCB&#xff08;注意&#xff0c;只需要转换出PCB即可&#xff0c;因为我们需要立创EDA的PCB库。不懂没关系&#xff0c;后面就清楚了&#xff09; &#…

把随身WiFi的esim卡移植到SIM卡放到手机使用

esim移植到实体sim卡&#xff0c;手把手教你esim改实体卡操作 自用先机的棒子&#xff0c;3-5倍虚标&#xff0c;在单位用&#xff0c;网速还行就是信号不好&#xff0c;uz801_v3.0的板子&#xff0c;410单天线&#xff0c;没有改装潜力&#xff0c;发热还大&#xff0c;加了风…

炸裂!速度百倍提升,高性能 Python 编译器 Codon 火了!

众所周知&#xff0c;Python 是一门简单易学、具有强大功能的编程语言&#xff0c;在各种用户使用统计榜单中总是名列前茅。相应地&#xff0c;围绕 Python&#xff0c;研究者开发了各种便捷工具&#xff0c;以更好的服务于这门语言。 编译器充当着高级语言与机器之间的翻译官…

[附源码]Nodejs计算机毕业设计基于Web企业客户管理系统Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分…

数据分析图表-FineReport 图表切换接口

1. 概述 1.1 问题描述 图表往往是按照从左往右或从右往左的顺序来切换。那么如何实现点击图表直接切换到其他不相邻的图表呢&#xff1f;效果如下图所示&#xff1a; 1.2 实现思路 给图表添加 JavaScript 类型的超级链接&#xff0c;调用图表接口FR.Chart.WebUtils.getChart(…

如何选择美股l2接口类型?

如何选择美股l2接口类型&#xff1f; 首先要选择稳定的美股l2接口&#xff0c;因为在进行股票行情分析的时候对于其数据的真实性和准确性都有很高的要求。不靠谱的数据平台容易造成数据传输卡顿&#xff0c;或数据获取不准确的情况&#xff0c;轻则影响企业运作&#xff0c;重…

SpringSecurity[6]-Thymeleaf中Spring Security的使用/退出登录/Spring Security中CSRF

上一篇:SpringSecurity[5]-基于表达式的访问控制/基于注解的访问控制/Remember Me功能实现 链接:SpringSecurity[4]-访问控制url匹配/内置访问控制方法介绍/角色权限判断_豆虫儿的博客-CSDN博客 十一、基于表达式的访问控制 十四、Thymeleaf中Spring Security的使用 Spring…

java计算机毕业设计基于安卓Android的校园财务流水系统APP

项目介绍 首先,论文一开始便是清楚的论述了系统的研究内容。其次,剖析系统需求分析,弄明白“做什么”,分析包括业务分析和业务流程的分析以及用例分析,更进一步明确系统的需求。然后在明白了系统的需求基础上需要进一步地设计系统,主要包罗软件架构模式、整体功能模块、数据库设…

Unity脚本基础

【重点面试题】1、Unity3D中的协程&#xff08;coroutine&#xff09;&#xff0c;C#线程和进程之间的区别是什么&#xff1f; 简记&#xff1a;协程和线程区别 协程(协同程序Coroutine): 同一时间只能执行某个协程。开辟多个协程开销不大。协程适合对某任务进行分时处理。 Un…

workerman+TP6实战网站客服系统之项目初始化

TP6 官方手册: 安装 ThinkPHP6.0完全开发手册 看云 安装TP6: composer create-project topthink/think tp6 报错: 解决问题: PHP默认把这个 proc_open 函数禁用了,取消禁用即可 取消禁用函数流程参考之前一篇文章 php workerman入门之运行起来_山山河川的博客-CSDN博…

Java中的匿名内部类

一、什么是匿名内部类&#xff1f; 定义&#xff1a;巴拉巴拉巴拉&#xff0c;就不写了。 语法&#xff1a; 部分内容来源于&#xff1a;什么是匿名内部类&#xff0c;如何使用匿名内部类_Weihaom_的博客-CSDN博客_匿名内部类 二、为什么要有匿名内部类&#xff1f; 在开发…

【大数据入门核心技术-Flume】(二)Flume安装部署

目录 一、准备工作 1、基本Hadoop环境安装 2、下载安装包 二、安装 1、解压 2、修改环境变量 3、修改并配置 flume-env.sh 文件 4、验证是否安装成功 一、准备工作 1、基本Hadoop环境安装 参考 Hadoop安装 【大数据入门核心技术-Hadoop】&#xff08;五&#xff09…

Spring WebSocket通信应用

文章目录前言一、客户端-服务端双向通信交互图二、项目说明1.引入包2.项目各模块说明问题参考前言 本文章主要记录项目客户端-服务端双向通信解决方案&#xff0c;基于Spring WebSocket架构实现双向数据通信; 以及项目实际应用中的一些问题与解决手段。一、客户端-服务端双向通…

[附源码]Node.js计算机毕业设计高铁乘坐舒适性在线调查及评价系统Express

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

挑灯夜战800个小时,终从外包成功上岸字节!入职那一天我眼眶湿润了

P8Java导图笔记 主目录&#xff1a; Java基础篇&#xff1a; JAVA基础对应详细解析文档 Java多线程并发篇&#xff1a; Java多线程并发知识点对应详解解析文档 JVM篇&#xff1a; JVM脑图对应详细文档解析 Spring原理 Spring原理对应详细解析文档 数据库 数据库对应详细解析文档…

[附源码]计算机毕业设计的连锁药店销售管理系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; Springboot mybatis MavenVue等等组成&#xff0c;B/S模式…

全面回顾2022年加密行业大事件:破后而立方能绝处逢生

2022年&#xff0c;加密领域以Luna/UST的崩溃为起点开启了漫长的加密寒冬&#xff0c;在严峻的宏观环境下以及一系列戏剧性事件中遭受了沉重打击。2022年初&#xff0c;加密货币生态系统的市值达到近3万亿美元&#xff0c;而截至年底已蒸发2万亿美元&#xff0c;随之消失的还有…

「秒杀购物商城业务服务」「分布式架构服务」盘点中间件服务

​ 秒杀购物商城业务服务-分布式架构介绍 基于MySQL数据库集群技术实现服务的高可用基于Tomcat的集群负载机制实现Tomcat服务器的高可用基于Nginx负载均衡机制实现负载均衡&#xff08;介绍和配置&#xff09;基于Redis缓存服务实现数据缓存控制相关介绍和技术点分析对未来的…