Files
2025-03-09 23:28:35 +08:00

131 lines
3.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
slug: "[C++ 筆記] 好用的 std::optional"
title: "[C++ 筆記] 好用的 std::optional"
description:
toc: true
authors:
- awin
tags:
- c++
categories:
- Programming
series:
- C++ 筆記
date: 2019-12-22T00:00:00
lastmod: 2019-12-22T00:00:00
featuredVideo:
featuredImage:
draft: false
enableComment: true
---
> since C++17
[`std::optional`](https://en.cppreference.com/w/cpp/utility/optional) 讓 function 的回傳值多了一個選擇:**有值**或是 `nullopt`
<!--more-->
例如我們有一個 function 要從某個檔案讀值出來(或是去 DB 查一個東西之類的需求),就假設我們要讀一個 int我們也許會這樣寫
```cpp
int readData(std::string filePath) {
...
int data = readFromFile(...);
...
return data;
}
```
但如果要讀的檔案不存在呢?這時候要 return 什麼呢?所以這時候我們會改成這樣寫:
```cpp
bool readData(std::string filePath, int& readData) {
FILE* file = fopen(...)
if (!file) {
return false;
}
readData = readFromFile(...);
return true;
}
```
我們用一個回傳值代表檔案讀取失敗與否,要是檔案存在且開啟成功,那麼 `readData` 這個回傳值就代表我們讀到的值。要是回傳值是 `false`,那 `readData` 就沒有意義。
但是這樣會讓傳入跟傳出的參數混在一起,第一時間也不容易直覺的分辨出來,像這種情況 Python 就清楚很多:
```python
def readData(filePath):
data = None
try:
with open(filePath, "rb") as f:
data = f.read(...)
return data
except FileNotFoundError as e:
return None
value = readData("123.txt")
if value:
pass # Do something...
```
可以像 Python 那樣都從回傳值來判斷嗎? `std::optional` 可以達到這個目的:
```cpp
std::optional<int> readData(std::string filePath) {
FILE* file = nullptr;
fopen_s(&file, filePath.c_str(), "rb");
if (!file) {
return std::nullopt;
}
int readData;
fread(&readData, 1, sizeof(readData), file);
fclose(file)
return readData;
}
auto result = readData("123.txt");
if (result) {
auto value = result.value();
// Use value here...
}
// 或是這樣寫也可以
if (result == std::nullopt) {
// Error handle here
} else {
auto value = result.value();
// Use value here...
}
```
雖然用起來沒辦法讓 C++ 像 Python 那麼簡單,但是 `std::optional` 確實讓整段 code 看起來更清楚了。
除了 [`std::optional<T>::value()`](https://en.cppreference.com/w/cpp/utility/optional/value) 以外,還有其他的取值方法:
```cpp
std::optional<std::string> name;
// Some process...
if (name)
{
printf("name = %s\n", (*name).c_str());
}
```
如果 `std::optional` 包含的是 struct 或是 class也可以用 `->` 來直接存取 member或 member function
```cpp
struct User {
uint32_t id;
std::string name;
int32_t age;
};
std::optional<User> user;
// Some process...
if (user) {
printf("id = %d\n", user->id);
printf("name = %s\n", user->name.c_str());
printf("age = %d\n", user->age);
}
```