当前位置: 首页 > news >正文

C++三剑客之std::optional(一) : 使用详解

相关文章系列

C++三剑客之std::optional(一) : 使用详解

C++三剑客之std::any(一) : 使用

C++之std::tuple(一) : 使用精讲(全)

C++三剑客之std::variant(一) : 使用

C++三剑客之std::variant(二):深入剖析

目录

1.概述

2.构建方式

2.1.默认构造

2.2.移动构造

2.3.拷贝构造

2.4.std::in_place_t构造

2.5.std::make_optional构造

3.修改器

3.1.operator=

3.2.emplace

3.3.reset

3.4.swap

4.观察器

4.1.operator->和operator*

4.2.operator bool和has_value

4.3.value

4.4.value_or

5.单子操作(C++23起)

5.1.and_then

5.2.transform

5.3.or_else

6.使用场景

7.注意事项

7.1.std::optional未初始化去访问

7.2.std::optional的比较操作

7.3.std::optional的生命周期

8.总结


1.概述

        C++17的三剑客分别是std::optional, std::any, std::vairant。今天主要讲std::optional。它是一个类模版,在头文件<<optional>>中定义,定义如下:

template< class T >
class optional;

        类模板 std::optional 管理一个可选 的容纳值,既可以存在也可以不存在的值。

        一种常见的 optional 使用情况是一个可能失败的函数的返回值。与其他手段,如 std::pair<T, bool> 相比,optional 良好地处理构造开销高昂的对象,并更加可读,因为它显式表达意图。

        以下是一个简单的代码示例,展示了如何在C++程序中引入和使用std::optional:

#include <optional>  // 引入std::optional
#include <iostream>std::optional<double> getValue(bool r) {if (r) {return 1.52;} else {return std::nullopt;}
}int main() {auto value = getValue(true);if (value.has_value()) {std::cout << "Value: " << *value << std::endl;} else {std::cout << "No value" << std::endl;}return 0;
}

在这个代码示例中,我们首先引入了<optional>头文件,然后定义了一个返回std::optional<double>的函数getValue。在main函数中,我们调用了getValue函数,并使用has_value成员函数检查返回值是否存在。如果存在,我们使用解引用运算符*来获取值。

2.构建方式

std::optional的构建方式主要有:

2.1.默认构造

std::optional的默认构造函数创建一个不包含值的std::optional对象。这在你需要延迟初始化或者表示一个可能不存在的值时非常有用。

std::optional<double> opt; // 创建一个不包含值的std::optional对象

2.2.移动构造

移动构造又称右值构造。你可以通过提供一个右值来构造std::optional对象。这个值将被复制或移动到新创建的std::optional对象中。如下示例:

std::optional<double> a(10.09); // 创建一个包含值10.09的std::optional对象
std::optional<double> b(std::move(a)); //使用移动构造函数创建一个新的std::optional对象

2.3.拷贝构造

如下示例:

std::optional<int> a(22222);
std::optional<int> b(a); // 使用拷贝构造函数创建一个新的std::optional对象

2.4.std::in_place_t构造

std::optional类还提供了in-place构造函数,允许你在std::optional对象的存储空间中直接构造值,避免了不必要的拷贝或移动操作。std::in_place是消除歧义的标签,其传递给ystd::optional的构造函数,用来指示原位构造对象。示例如下:

#include <iostream>
#include <optional>
#include <string>int main()
{// 调用 std::string( initializer_list<CharT> ) 构造函数std::optional<std::string> o4(std::in_place, {'a', 'b', 'c'});// 调用 std::string( size_type count, CharT ch ) 构造函数std::optional<std::string> o5(std::in_place, 3, 'A');// 从 std::string 移动构造,用推导指引拾取类型std::optional o6(std::string{"deduction"});std::cout << *o2 << ' ' << *o3 << ' ' << *o4 << ' ' << *o5  << ' ' << *o6 << '\n';
}

输出:1 1 abc AAA deduction

2.5.std::make_optional构造

创建一个包含给定值的std::optional对象,它的定义如下:

从定义看出,可以从右值,可变参数和std::initializer_list等多种方式用std::make_optional构造出std::optional对象。示例如下:

#include <optional>
#include <iostream>
#include <iomanip>
#include <vector>
#include <string>int main()
{auto op1 = std::make_optional<std::vector<char>>({'a','b','c'});std::cout << "op1: ";for (char c: op1.value()){std::cout << c << ",";}auto op2 = std::make_optional<std::vector<int>>(5, 2);std::cout << "\nop2: ";for (int i: *op2){std::cout << i << ",";}std::string str{"hello world"};auto op3 = std::make_optional<std::string>(std::move(str));std::cout << "\nop3: " << quoted(op3.value_or("empty value")) << '\n';std::cout << "str: " << std::quoted(str) << '\n';
}

输出:

op1: a,b,c,
op2: 2,2,2,2,2,
op3: "hello world"
str: 

3.修改器

3.1.operator=

对内容赋值,重载operator=操作符的类型有:

从中看出std::optional的赋值函数参数包括std::nullopt_t、左值引用、右值引用、模板单值、模板做值和模板右值。示例如下:

#include <optional>
#include <iostream>
int main()
{std::optional<const char*> s1 = "abc", s2; // 构造函数s2 = s1; // 赋值s1 = "def"; // 衰变赋值( U = char[4], T = const char* )std::cout << *s2 << ' ' << *s1 << '\n';
}

输出:abc def

3.2.emplace

emplace的定义如下:

示例如下:

#include <optional>
#include <iostream>struct A {std::string s;A(std::string str) : s(std::move(str))  { std::cout << " constructed\n"; }~A() { std::cout << " destructed\n"; }A(const A& o) : s(o.s) { std::cout << " copy constructed\n"; }A(A&& o) : s(std::move(o.s)) { std::cout << " move constructed\n"; }A& operator=(const A& other) {s = other.s;std::cout << " copy assigned\n";return *this;}A& operator=(A&& other) {s = std::move(other.s);std::cout << " move assigned\n";return *this;}
};int main()
{std::optional<int> a;a.emplace(10); // 在optional对象中就地构造一个值std::optional<A> opt;std::cout << "Assign:\n";opt = A("Lorem ipsum dolor sit amet, consectetur adipiscing elit nec.");std::cout << "Emplace:\n";// 由于 opt 含值,这亦将销毁该值opt.emplace("Lorem ipsum dolor sit amet, consectetur efficitur. ");std::cout << "End example\n";
}

输出:

Assign:constructedmove constructeddestructed
Emplace:destructedconstructed
End exampledestructed

3.3.reset

重置对象,若 std::optional 含值,则如同用 value().T::~T() 销毁此值。否则无效果。示例如下:

#include <optional>
#include <iostream>struct A {std::string s;A(std::string str) : s(std::move(str))  { std::cout << " constructed\n"; }~A() { std::cout << " destructed\n"; }A(const A& o) : s(o.s) { std::cout << " copy constructed\n"; }A(A&& o) : s(std::move(o.s)) { std::cout << " move constructed\n"; }A& operator=(const A& other) {s = other.s;std::cout << " copy assigned\n";return *this;}A& operator=(A&& other) {s = std::move(other.s);std::cout << " move assigned\n";return *this;}
};int main()
{std::cout << "Create empty optional:\n";std::optional<A> opt;std::cout << "Construct and assign value:\n";opt = A("Lorem ipsum dolor sit amet, consectetur adipiscing elit nec.");std::cout << "Reset optional:\n";opt.reset();std::cout << "End example\n";
}

输出:

Create empty optional:
Construct and assign value:constructedmove constructeddestructed
Reset optional:destructed
End example

3.4.swap

交换内容,如果内部有值,这先析构内部值,再交换值。示例如下:

#include <iostream>
#include <string>
#include <optional>int main()
{std::optional<std::string> opt1("First example text");std::optional<std::string> opt2("2nd text");enum Swap { Before, After };auto print_opts = [&](Swap e) {std::cout << (e == Before ? "Before swap:\n" : "After swap:\n");std::cout << "opt1 contains '" << opt1.value_or("") << "'\n";std::cout << "opt2 contains '" << opt2.value_or("") << "'\n";std::cout << (e == Before ? "---SWAP---\n": "\n");};print_opts(Before);opt1.swap(opt2);print_opts(After);// 在仅一者含值时交换opt1 = "Lorem ipsum dolor sit amet, consectetur tincidunt.";opt2.reset();print_opts(Before);opt1.swap(opt2);print_opts(After);
}

输出:

Before swap:
opt1 contains 'First example text'
opt2 contains '2nd text'
---SWAP---
After swap:
opt1 contains '2nd text'
opt2 contains 'First example text'Before swap:
opt1 contains 'Lorem ipsum dolor sit amet, consectetur tincidunt.'
opt2 contains ''
---SWAP---
After swap:
opt1 contains ''
opt2 contains 'Lorem ipsum dolor sit amet, consectetur tincidunt.'

4.观察器

4.1.operator->和operator*

operator->返回所含值的指针;operator*返回所函数的引用,

此运算符不检查 std::optional 是否含值!你能手动用 has_value() 或简单地用 operator bool() 做检查。另外,若需要有检查访问,可使用 value() 或 value_or() 。

示例如下:

#include <optional>
#include <iostream>
#include <string>int main()
{using namespace std::string_literals;std::optional<int> opt1 = 1;std::cout<< "opt1: "  << *opt1 << '\n';*opt1 = 2;std::cout<< "opt1: "  << *opt1 << '\n';std::optional<std::string> opt2 = "abc"s;std::cout<< "opt2: " << *opt2 << " size: " << opt2->size() << '\n';// 你能通过在到 optional 的右值上调用 operator* “取”其所含值auto taken = *std::move(opt2);std::cout << "taken: " << taken << " opt2: " << *opt2 << "size: " << opt2->size()  << '\n';
}

输出:

opt1: 1
opt1: 2
opt2: abc size: 3
taken: abc opt2: size: 0

4.2.operator bool和has_value

检查std::optional是否函数,这个比较简单,这里就不赘述了。

4.3.value

若 std::optional含值,则返回到所含值引用,示例如下:

#include <optional>
#include <iostream>
int main()
{std::optional<int> opt = {};try {int n = opt.value();} catch(const std::exception& e) {std::cout << e.what() << '\n';}
}

输出:bad optional access

4.4.value_or

value_or的定义如下:

若std::optional 拥有值则返回其所含的值,否则返回 default_value 。

1) 等价于 bool(*this) ? **this : static_cast<T>(std::forward<U>(default_value))

2) 等价于 bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(default_value))

示例如下:

#include <optional>
#include <iostream>
#include <cstdlib>std::optional<const char*> maybe_getenv(const char* n)
{if(const char* x = std::getenv(n))return x;elsereturn {};
}
int main()
{std::cout << maybe_getenv("MYPWD").value_or("(none)") << '\n';
}

输出:(none)

5.单子操作(C++23起)

5.1.and_then

在所含值存在时返回对其应用给定的函数的结果,否则返回空的 std::optional。下面示例可能包括C++23的部分内容,不清楚的地方可以去查询相关文档。代码如下:

#include <charconv>
#include <iomanip>
#include <iostream>
#include <optional>
#include <ranges>
#include <string>
#include <string_view>
#include <vector>std::optional<int> to_int(std::string_view sv)
{int r {};auto [ptr, ec] { std::from_chars(sv.data(), sv.data() + sv.size(), r) };if (ec == std::errc())return r;elsereturn std::nullopt;
}int main()
{using namespace std::literals;const std::vector<std::optional<std::string>> v{"1234", "15 foo", "bar", "42", "5000000000", " 5", std::nullopt, "-43"};for (auto&& x : v | std::views::transform([](auto&& o){// 调试打印输入的 optional<string> 的内容std::cout << std::left << std::setw(13)<< std::quoted(o.value_or("nullopt")) << " -> ";return o// 若 optional 为空则转换它为持有 "" 字符串的 optional.or_else([]{ return std::optional{""s}; })// 拉平映射 string 为 int (失败时产生空的 optional).and_then(to_int)// 映射 int 为 int + 1.transform([](int n) { return n + 1; })// 转换回 string.transform([](int n) { return std::to_string(n); })// 以 and_than 替换,并用 "NaN" 变换并忽略所有剩余的空 optional// and_then and ignored by transforms with "NaN".value_or("NaN"s);}))std::cout << x << '\n';
}

输出:

"1234"        -> 1235
"15 foo"      -> 16
"bar"         -> NaN
"42"          -> 43
"5000000000"  -> NaN
" 5"          -> NaN
"nullopt"     -> NaN
"-43"         -> -42

5.2.transform

在所含值存在时返回含有变换后的所含值的 std::optional,否则返回空的 std::optional。示例如下:

#include <iostream>
#include <optional>struct A { /* ... */ };
struct B { /* ... */ };
struct C { /* ... */ };
struct D { /* ... */ };auto A_to_B(A) -> B { /* ... */ std::cout << "A => B \n"; return {}; }
auto B_to_C(B) -> C { /* ... */ std::cout << "B => C \n"; return {}; }
auto C_to_D(C) -> D { /* ... */ std::cout << "C => D \n"; return {}; }void try_transform_A_to_D(std::optional<A> o_A)
{std::cout << (o_A ? "o_A has a value\n" : "o_A is empty\n");std::optional<D> o_D = o_A.transform(A_to_B).transform(B_to_C).transform(C_to_D);std::cout << (o_D ? "o_D has a value\n\n" : "o_D is empty\n\n");
};int main()
{try_transform_A_to_D( A{} );try_transform_A_to_D( {} );
}

输出:

o_A has a value
A => B
B => C
C => D
o_D has a valueo_A is empty
o_D is empty

5.3.or_else

在 std::optional 含值时返回自身,否则返回给定函数的结果。功能比较简单,在这里就不在赘述了。

6.使用场景

函数返回值:当函数可能返回一个值,也可能不返回值时,可以使用std:optional作为返回类型。这种方式可以避免使用指针或特殊值来表示无值的情况,从而提高代码的简洁性和安全性。

参数传递:将std::optional作为数参数,可以接受或忽略该参数的值。这种方式可以使函数更加灵活,适应不同的情况。

容器类:可以使用std:optional作为容器类(如std:vector、std:list等)的元素类型,以存储可能不存在的值。这种方式可以方便地处理容器中的空值,而无需使用指针或特殊值。

可选状态:当某个对象可能处于某种状态,也可能不处于该状态时,可以使用std:optional来表示该状态。例如,一个购物车可能包含一个可选的运费,可以使用std::optional<double>来表示是否计算运费。

异步编程:在异步编程中std:optional可以用于表示异步操作的结果。例如,一个异步函数可能返回一个std::optional<int>表示异步计算的结果可能是一个整数值,或者没有结果(空值)。

7.注意事项

在使用C++的std::optional类时,有一些重要的注意事项需要我们了解。这些注意事项可以帮助我们更好地理解和使用std::optional类,避免在编程中出现错误。

7.1.std::optional未初始化去访问

当我们创建一个std::optional对象但没有给它赋值时,这个对象就处于未初始化的状态。在这种状态下,如果我们试图访问它的值,就会抛出std::bad_optional_access异常。

std::optional<int> a;
try {int value = a.value();  // 抛出std::bad_optional_access
} catch (const std::bad_optional_access& e) {std::cout << e.what() << '\n';
}

在这个例子中,我们创建了一个未初始化的std::optional对象,并试图访问它的值。这会抛出一个std::bad_optional_access异常,我们可以捕获这个异常并处理它。

在实际编程中,我们应该在访问std::optional的值之前,先使用has_value()函数或者bool运算符检查它是否已经被初始化。

std::optional<int> a;
if (a) {  // 或者 if (a.has_value())int value = a.value();
}

7.2.std::optional的比较操作

std::optional支持所有的比较操作,包括==, !=, <, <=, >, >=。这些比较操作首先会比较两个std::optional对象的初始化状态,然后再比较它们的值。

std::optional<int> a= 1;
std::optional<int> b= 2;
std::optional<int> b;std::cout << (a == b) << '\n';  // 输出0,因为a和b的值不相等
std::cout << (a == c) << '\n';  // 输出0,因为a已经初始化,而c未初始化
std::cout << (c == std::nullopt) << '\n';  // 输出1,因为c未初始化

在这个例子中,我们创建了两个已经初始化的std::optional对象和一个未初始化的std::optional对象,然后比较它们的值和初始化状态。

7.3.std::optional的生命周期

std::optional的生命周期和它包含的值的生命周期是一致的。当std::optional被销毁时,它包含的值也会被销毁。这意味着我们不能返回一个包含局部变量的std::optional。

std::optional<std::string> getName(bool c) {
std::string name = "zdxiao";
if (c) {return name;  // 错误:返回一个包含局部变量的std::optional
}
return std::nullopt;

在这个例子中,我们试图返回一个包含局部变量name的std::optional<std::string>。但是当getName函数返回时,name变量会被销毁,所以返回的std::optional<std::string>会包含一个已经被销毁的值。

在实际编程中,我们应该避免返回包含局部变量的std::optional。我们可以返回一个值,或者返回std::nullopt_t表示没有值。

std::optional<std::string> getName(bool c) {
if (c) {return "zdxiao";  // 正确:返回一个值
}return std::nullopt;  // 正确:表示没有值
}

在这个修改后的例子中,我们返回一个字符串字面量,而不是一个局部变量。这样返回的std::optionalstd::string就会包含一个有效的值。

以上就是在使用std::optional类时需要注意的一些重要事项。在实际编程中,我们应该充分理解和掌握这些注意事项,以避免在编程中出现错误。

8.总结

上面全面讲解了std::optional的用法和一些注意事项,要想深入理解它,那就需要在平时的工作中慢慢的去使用它,细细体会,才能真正领会发明std::optional的意义。

参考:std::optional - cppreference.com

相关文章:

C++三剑客之std::optional(一) : 使用详解

相关文章系列 C三剑客之std::optional(一) : 使用详解 C三剑客之std::any(一) : 使用 C之std::tuple(一) : 使用精讲(全) C三剑客之std::variant(一) : 使用 C三剑客之std::variant(二)&#xff1a;深入剖析 目录 1.概述 2.构建方式 2.1.默认构造 2.2.移动构造 2.3.拷贝构…...

网络安全漏洞管理十大度量指标

当前&#xff0c;网络安全漏洞所带来的风险及产生的后果&#xff0c;影响到网络空间乃至现实世界的方方面面&#xff0c;通信、金融、能源、电力、铁路、医院、水务、航空、制造业等行业各类勒索、数据泄露、供应链、钓鱼等网络安全攻击事件层出不穷。因此&#xff0c;加强对漏…...

Swift Combine 发布者订阅者操作者 从入门到精通二

Combine 系列 Swift Combine 从入门到精通一 1. Combine核心概念 你只需要了解几个核心概念&#xff0c;就能使用好 Combine&#xff0c;但理解它们非常重要。 这些概念中的每一个都通过通用协议反映在框架中&#xff0c;以将概念转化为预期的功能。 这些核心概念是&#x…...

python 笔记:shapely(形状篇)

主要是点&#xff08;point&#xff09;、线&#xff08;linestring&#xff09;、面&#xff08;surface&#xff09; 1 基本方法和属性 object.area 返回对象的面积&#xff08;浮点数&#xff09; object.bounds 返回一个&#xff08;minx, miny, maxx, maxy&#xff09;元…...

开源的JS动画框架库介绍

开源的JS动画框架库介绍 在现代网页设计中&#xff0c;动画已经成为提升用户体验的重要手段。它们不仅能够吸引用户的注意力&#xff0c;还能够帮助用户更好地理解和导航网站。JavaScript 动画框架库提供了一套丰富的动画效果&#xff0c;让开发者能够轻松地实现复杂的…...

MATLAB实现随机森林回归算法

随机森林回归是一种基于集成学习的机器学习算法&#xff0c;它通过组合多个决策树来进行回归任务。随机森林的基本思想是通过构建多个决策树&#xff0c;并将它们的预测结果进行平均或投票来提高模型的准确性和鲁棒性。 以下是随机森林回归的主要特点和步骤&#xff1a; 决策树…...

时间序列预测——BiGRU模型

时间序列预测——BiGRU模型 时间序列预测是指根据历史数据的模式来预测未来时间点的值或趋势的过程。在深度学习领域&#xff0c;循环神经网络&#xff08;Recurrent Neural Networks, RNNs&#xff09;是常用于时间序列预测的模型之一。在RNNs的基础上&#xff0c;GRU&#x…...

django中实现数据库操作

在Django中&#xff0c;数据库操作通常通过Django的ORM&#xff08;Object-Relational Mapping&#xff09;来实现。ORM允许你使用Python类来表示数据库表&#xff0c;并可以使用Python语法来查询和操作数据库。 以下是在Django中实现数据库操作的基本步骤&#xff1a; 一&am…...

使用 FFmpeg 将视频转换为 GIF 动画的技巧

使用 FFmpeg 将视频转换为 GIF 动画 FFmpeg 可以将视频转换为 GIF 动画&#xff0c;方法如下&#xff1a; 1. 准备工作 确保您已经安装了 FFmpeg。 熟悉 FFmpeg 的命令行使用。 了解 GIF 动画的基本知识。 2. 基本命令 ffmpeg -i input.mp4 output.gif 3. 参数说明 -i in…...

2024春晚纸牌魔术原理----环形链表的约瑟夫问题

一.题目及剖析 https://www.nowcoder.com/practice/41c399fdb6004b31a6cbb047c641ed8a?tabnote 这道题涉及到数学原理,有一般公式,但我们先不用公式,看看如何用链表模拟出这一过程 二.思路引入 思路很简单,就试创建一个单向循环链表,然后模拟报数,删去对应的节点 三.代码引…...

HCIA-HarmonyOS设备开发认证V2.0-轻量系统内核内存管理-静态内存

目录 一、内存管理二、静态内存2.1、静态内存运行机制2.2、静态内存开发流程2.3、静态内存接口2.4、实例2.5、代码分析&#xff08;待续...&#xff09;坚持就有收货 一、内存管理 内存管理模块管理系统的内存资源&#xff0c;它是操作系统的核心模块之一&#xff0c;主要包括…...

什么是vite,如何使用

参考&#xff1a; 主要&#xff1a;由一次业务项目落地 Vite 的经历&#xff0c;我重新理解了 Vite 预构建 vite官方文档 为什么有人说 vite 快&#xff0c;有人却说 vite 慢&#xff1f; 深入理解Vite核心原理 面向未来的前端构建工具-vite 聊一聊 Vite 的预构建和二次预构建 …...

基于大语言模型的AI Agents

代理&#xff08;Agent&#xff09;指能自主感知环境并采取行动实现目标的智能体。基于大语言模型&#xff08;LLM&#xff09;的 AI Agent 利用 LLM 进行记忆检索、决策推理和行动顺序选择等&#xff0c;把Agent的智能程度提升到了新的高度。LLM驱动的Agent具体是怎么做的呢&a…...

23种设计模式之抽象工厂模式

目录 什么是抽象工厂模式 基本结构 基本实现步骤 实现代码&#xff08;有注释&#xff09; 应用场景 简单工厂、工厂方法、抽象工厂的区别 什么是抽象工厂模式 抽象工厂模式也是一种创建型设计模式&#xff0c;提供了一系列相关或相互依赖对象的接口&#xff0c;而无需…...

飞天使-linux操作的一些技巧与知识点9-zabbix6.0 容器之纸飞机告警设置

文章目录 zabbix 告警纸飞机方式webhook 方式 告警设置 zabbix 告警纸飞机方式 第一种方式参考 https://blog.csdn.net/yetugeng/article/details/99682432bash-4.4$ cat telegram.sh #!/bin/bashMSG$1TOKEN"61231432278:AAsdfsdfsdfsdHUxBwPSINc2kfOGhVik" CHAT_I…...

京东组件移动端库的使用 Nut-UI

1.介绍 NutUI NutUI-Vue 组件库&#xff0c;基于 Taro&#xff0c;使用 Vue 技术栈开发小程序应用&#xff0c;开箱即用&#xff0c;帮助研发快速开发用户界面&#xff0c;提升开发效率&#xff0c;改善开发体验。 特性 &#x1f680; 80 高质量组件&#xff0c;覆盖移动端主…...

用Python来实现2024年春晚刘谦魔术

简介 这是新春的第一篇&#xff0c;今天早上睡到了自然醒&#xff0c;打开手机刷视频就被刘谦的魔术所吸引&#xff0c;忍不住用编程去模拟一下这个过程。 首先&#xff0c;声明的一点&#xff0c;大年初一不学习&#xff0c;所以这其中涉及的数学原理约瑟夫环大家可以找找其…...

TestNG基础教程

TestNG基础教程 一、常用断言二、执行顺序三、依赖测试四、参数化测试1、通过dataProvider实现2、通过xml配置&#xff08;这里是直接跑xml&#xff09; 五、testng.xml常用配置方式1、分组维度控制2、类维度配置3、包维度配置 六、TestNG并发测试1、通过注解来实现2、通过xml来…...

###51单片机学习(1)-----单片机烧录软件的使用,以及如何建立一个工程项目

前言&#xff1a;感谢您的关注哦&#xff0c;我会持续更新编程相关知识&#xff0c;愿您在这里有所收获。如果有任何问题&#xff0c;欢迎沟通交流&#xff01;期待与您在学习编程的道路上共同进步。 一. 两个主要软件的介绍 1.KeiluVision5软件 Keil uVision5是一款集成开发…...

Android 9.0 任务栏中清除掉播放器的进程,状态栏仍有音乐播放器状态问题的解决

1.概述 在9.0的rom定制化开发中,在点击系统自带的播放器以后,播放音乐的时候,在最近任务栏recents列表中,点击全部清除,发现音乐播放器还在播放音乐,导致出现bug,完整的 解决方法,肯定是需要点击全部清除以后,音乐播放器也被杀掉进程,接下来分析下这个移除任务栏流程…...

【笔记】Helm-5 Chart模板指南-13 调是模版

调试模板 调试模板可能很棘手&#xff0c;因为渲染后的模板发送了kubernetes API server&#xff0c;可能会以格式化以外的原因拒绝YAML文件。 以下命令有助于调试&#xff1a; 1、helm lint 是验证chart是否遵循最佳实践的首选工具。 2、helm template --debug在本地测试渲…...

Gateway反向代理配置

前言 一般而言&#xff0c;反向代理都是在Nginx中来实现的&#xff0c;其实Gateway也可以作为反向代理服务&#xff0c;不过一般不会这么做&#xff0c;只不过最近的项目&#xff0c;在通过Nginx反向代理之后&#xff0c;iPhone手机访问接口代理地址会异常&#xff0c;安卓手机…...

HiveSQL——共同使用ip的用户检测问题【自关联问题】

注&#xff1a;参考文章&#xff1a; SQL 之共同使用ip用户检测问题【自关联问题】-HQL面试题48【拼多多面试题】_hive sql 自关联-CSDN博客文章浏览阅读810次。0 问题描述create table log( uid char(10), ip char(15), time timestamp);insert into log valuesinsert into l…...

猫头虎分享已解决Bug ‍ || 修改mongodb3.0副本集用户密码遇到 BeanDefinitionParsingException

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …...

如何将ChatGPT升级到4.0版本?如何充值?

如何将ChatGPT升级到4.0版本&#xff1f; 在人工智能的世界里&#xff0c;每一个升级都可能带来革命性的变革。ChatGPT的4.0版本无疑是当前最炙手可热的话题之一&#xff0c;那么如何进行升级&#xff0c;体验到这一版所带来的全新特性呢&#xff1f;以下是一步一步的指南。 …...

conda 相关命令

创建并激活环境&#xff1a;打开终端&#xff0c;并创建一个新的conda环境&#xff0c;以确保安装的软件与M1芯片兼容。运行以下命令&#xff1a; conda create -n myenv python这将创建一个名为"myenv"的新环境&#xff0c;并安装Python。然后&#xff0c;激活该环境…...

探索现代Web前端开发框架:选择最适合你的工具

在当今快速发展的Web开发领域&#xff0c;前端开发框架的选择显得尤为关键。这些框架可以帮助我们更高效地构建出交互性强、性能卓越的用户界面。本文将带你了解几个当前最受欢迎的Web前端开发框架&#xff0c;并帮助你根据自己的需求选择最合适的工具。 1. React React由Fac…...

记录一下,我使用stm32实现pwm波输入,以及对频率和占空比的计算,同时通过串口输出(实现-重要)

1&#xff0c;首先看下半物理仿真 看下我的配置&#xff1a; 看下计算方法以及matlab的仿真输出的数据&#xff1a; timer3的ch2是选择高电平&#xff0c;计算频率 timer3的ch1是选择的是低电平&#xff0c;用来计算周期 其中TemPIpre表示的是CH2输出的值&#xff0c; TemPI…...

Spring Cloud使用ZooKeeper作为注册中心的示例

简单的Spring Cloud应用程序使用ZooKeeper作为注册中心的示例&#xff1a; 1.新建模块&#xff1a; 2.勾选依赖&#xff1a; 3.在pom.xml文件中做出部分修改及添加Spring Cloud Zookeeper 依赖版本&#xff1a; 完整pom文件 <?xml version"1.0" encoding&q…...

【项目日记(九)】项目整体测试,优化以及缺陷分析

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:项目日记-高并发内存池⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你做项目   &#x1f51d;&#x1f51d; 开发环境: Visual Studio 2022 项目日…...

网站建设的工作描述/网站推广策略有哪些

当你在一个类似批处理的脚本里启动多个shell脚本的时候&#xff0c;可能没有意识到shell背后的调度器会将这些脚本在多个CPU上并行执行。当同时执行的脚本访问某些共享资源(通常是文件)时&#xff0c;可能造成执行的结果错误&#xff0c;而且经常让你意识不到。 不同于低级语言…...

备案用网站建设方案/网络营销教材电子版

1.webstorm代码编辑IDE神器。 2.想要便捷轻快编写代码 atom、vs code、sublime 3.Zeplin可以很好的标出PSD格式的图的长宽高间距大小 4.sourceTree git专用 5.微信web开发者工具&#xff0c;开发微信页面专用可调试 5.charles抓包神器 转载于:https://www.cnblogs.com/c-zhangy…...

柬埔寨做网站/浏览器老是出现站长工具

中国气象局与交通运输部2021年07月22日联合发布全国主要公路气象预报7月22日20时至23日20时&#xff0c;内蒙古东北部、黑龙江西北部、西藏南部、陕西南部、黄淮西部、浙江中东部、四川盆地东南部、云南、广西西南部和沿海、广东西南部、海南岛等地部分地区有中到大雨&#xff…...

做资源的教育类网站或公司/百度大数据分析平台

Hibernate-memcached是CacheProvider接口的memcached实现 http://code.google.com/p/hibernate-memcached/ 步骤&#xff1a; one&#xff1a;下载和安装运行memcache服务器程序 即&#xff1a;memcache.exe 下载到c&#xff1a;\ two:增加Hibernate-memcached的相…...

微信公众号手机上传wordpress/网络营销服务策略

获取公众号文章消息链接 (JAVA) 需求: APP用户分享视频后生成自己的带货链接。 坑爹啊 这链接从哪来的。。。去看微信公众号文档又是一头雾水。 整理&#xff1a;(不一定是用我这种方法&#xff0c;但我找不到其他方法了。) 思路&#xff1a;首先知道这个链接可以在 公众号给…...

衢州做网站公司/企业seo推广的绝密诀窍曝光

题目 题目链接 题解 SB题。做不出来就算了。 题目给的图很难看出和“十字型”有鸡毛关系。 还是看我打印出来的吧。因为原图给的dollar符是斜体&#xff0c;所以很难观察出规律。 还是自己尝试着打印吧&#xff0c;不同人不同思路。 我的思路&#xff1a;图是中心对称的&am…...