解包/打包操作员

Unpack / pack operator

提问人:David542 提问时间:8/9/2023 最后编辑:David542 更新时间:8/18/2023 访问量:264

问:

我正在寻找实现打包/拆包操作员的各种方法。举个例子:

*[1,2,3]    --> 1,2,3     (one array scalar value unpacked to three values)
*1,2,3      --> [1,2,3]   (three values packed to one scalar array value)

这是语言中的常见运算符吗?如果是这样,它通常如何表示?

其他可能的术语:

  • 解构/结构化
  • 开箱/打包
C++ 解析 编译器-构造 运算符-关键字 语言设计

评论

0赞 n. m. could be an AI 8/12/2023
这个问题相当不清楚。您在寻找句法形式吗?对于转换为机器代码的方法?
0赞 David542 8/12/2023
@n.m.couldbeanAI 更多句法形式
6赞 templatetypedef 8/13/2023
我看到这个问题被标记为 C++,但我在问题正文中没有看到任何专门针对 C++ 的内容。你能澄清一下吗?谢谢!

答:

3赞 Patricio Loncomilla 8/12/2023 #1

实现此目的的方法取决于语言。

在 python 中,可以使用元组打包/解包值:

mytuple = (1,2,3)   # Packing into a tuple
(a,b,c) = mytuple   # Unpacking
print(f'{a}, {b}, {c}')

在 c++11 中,可以使用以下方法完成:std::tie()

#include <iostream>
#include <tuple>

int main()
{
    auto mytuple = std::tuple<int,int,int>{1,2,3}; // Packing into a tuple
    int a, b, c;
    std::tie(a,b,c) = mytuple;                     // Unpacking (std::tie)
    std::cout << a << " " << b << " " << c << std::endl;
    return 0;
}

而且,在 c++17 及更高版本中,可以使用结构化绑定:

#include <iostream>
#include <tuple>

int main()
{
    auto mytuple = std::tuple{1,2,3}; // Packing into a tuple
    auto[a,b,c] = mytuple;            // Unpacking (structured binding)
    std::cout << a << " " << b << " " << c << std::endl;
    return 0;
}
1赞 Shashank saxena 8/13/2023 #2

打包和解包,也称为解构和结构化,是许多编程语言中的常见概念。它允许在单个语句中将多个值分配给多个变量,或者将多个值作为参数传递给函数。

在 C++ 中,可以使用结构化绑定(从 C++17 开始)将数组或元组的元素解压缩为单独的变量:

#include <array>
#include <iostream>
#include <tuple>

int main() {
     std::array<int, 3> myarray = {1, 2, 3};
     auto [a, b, c] = myarray;
     std::cout << a << ' ' << b << ' ' << c << '\n'; // prints 1 2 3

     std::tuple<int, int, int> mytuple = {4, 5, 6};
     auto [x, y, z] = mytuple;
     std::cout << x << ' ' << y << ' ' << z << '\n'; // prints 4 5 6
     }

在 JavaScript 中,展开运算符 (...) 用于解包。它的工作方式类似于 Python 中的星号运算符:

function myfunc(a, b, c) {
    console.log(a, b, c);
}

let myarray = [1, 2, 3];
myfunc(...myarray); // prints 1 2 3

在 Python 中,星号 (*) 运算符用于解包。例如,您可以使用它来解压缩列表或元组的元素,并将它们作为单独的参数传递给函数:

def myfunc(a, b, c):
    print(a, b, c)

mylist = [1, 2, 3]
myfunc(*mylist) # prints 1 2 3

语法和行为可能因语言及其版本而异

2赞 Alireza Roshanzamir 8/14/2023 #3

我将描述Python中的整个相关工作和语法。

将变量打包为集合,并将可迭代文件解压缩为某些变量:

iterable = (1, 2, 3, 4)  # Packing by Tuple explicitly
iterable = 1, 2, 3, 4  # Packing by Tuple implicitly
iterable = [1, 2, 3, 4]  # Packing by List
nested_iterable = (1, 2, (4, 5, 6))  # Packing nested items
mapping = {"a": 1, "b": 2}

a, b, c, d = iterable  # Unpacking using Tuple implicitly
(a, b, c, d) = iterable  # Unpacking using Tuple explicitly
[a, b, c, d] = iterable  # Unpacking using List
a, _, _, d = iterable  # Ignoring some values by conventionally using the _ (called Throwaway) variable
a, *middle_items, d = iterable  # Using * to group remaining items as a List
a, b, c, *d = iterable  # Using * for a single element is also grouped as a single item List
a, b, c, d, *e = iterable  # If there are no other elements, e becomes an empty List
a, *_ = iterable  # Ignoring remaining items
a, b, (c, d, e) = nested_iterable  # Unpacking nested items using Tuple
a, b, [c, d, e] = nested_iterable  # Unpacking nested items using mixed Tuple and List
a_key, b_key = mapping  # The items get iterated for unpacking, so, here, only keys got returned
(a_key, a_value), (b_key, b_value) = mapping.items()  # Unpacking a mapping using items method

注意:不能在一次解包中多次应用运算符。*

将可迭代对象解压缩为位置参数,将映射解压缩为命名参数,以及打包剩余的位置和命名参数:

def normal_function(a, b, c, d):
    ...

items = [2, 3, 4, 5]
mapping = {"a": 2, "b": 3, "c": 4, "d": 5}

normal_function(*items)  # Positional unpacking to function arguments.
normal_function(**mapping)  # Named unpacking to function arguments.

def variadic_function(a, b, c, *remaining_positional_args, d, e, f, **remaining_named_args):
    # remaining_positional_args is a Tuple and remaining_named_args is a Dict
    # d, e, f must be filled by the name
    ...
0赞 k0uva 8/16/2023 #4

以下是数组解构和结构化在不同语言中的实现方式:

JS的

解构:

const [a, b, c] = [1, 2, 3]; // Unpacks the array into individual variables a, b, and c

构建:

const packedArray = [a, b, c]; // Packs the values into a new array

解构:

a, b, c = (1, 2, 3)  # Unpacks the tuple into individual variables a, b, and c

构建:

packed_tuple = (a, b, c)  # Packs the values into a new tuple

CPP系列

C++ 没有像 JavaScript 或 Python 那样用于数组解构或结构化的直接内置机制。但是,您可以使用以下方法获得类似的结果:

解构: 您可以手动将数组中的值分配给各个变量。

int arr[] = {1, 2, 3};
int a = arr[0];
int b = arr[1];
int c = arr[2];

构建: 您可以创建数组或数据结构来保存这些值。

int a = 1;
int b = 2;
int c = 3;
int arr[] = {a, b, c};
1赞 Enlico 8/18/2023 #5

你提到了数组,但打包和解包只是分别意味着,在将整个包传递给函数之前,从多个实体中产生 1 个边界,并将包的组成部分作为单独的参数传递给函数。

实际的捆绑包(数组、元组、结构)是一种实现细节,只要你有办法从成分中创建一个,并且有办法从成分中拉出。

在 C++ 中,a 是首选,因为这样可以自由选择可以捆绑在一起的实体的数量和类型。A 会限制你对所有实体使用相同的类型,所以在大多数场景中都是不可能的。std::tuplestd::array

因此,当您想在将更多实体传递给函数之前将它们打包在一起时,只需使用 .std::make_tuple

对于解包,情况更加复杂,但幸运的是有一些现成的库解决方案:Boost.Hana 提供 boost::hana::unpack,它允许你做这样的事情

constexpr auto add = [](auto x, auto y, auto z) {
    return x + y + z;
};
std::cout << hana::unpack(hana::make_tuple(1, 2, 3), add); // prints 6

(该示例使用 boost::hana::tuple,但扩展 Hana 也很容易为 s 工作。hana::unpackstd::tuple

在这方面,结构化绑定是一种最小的构建块,因为它们允许您在将单个实体传递给所需函数之前为它们命名。参考上面的例子,你可以把它改写成std::tie

constexpr auto add = [](auto x, auto y, auto z) {
    return x + y + z;
};
auto const& [a, b, c] = std::make_tuple(1, 2, 3);
std::cout << add(a, b, c); // prints 6

这有点麻烦,因为你必须发明一个实际上可能没有多大意义的名字,这取决于具体情况,很明显;很明显,如果元组只是不相关事物的集合,它们将采用不相关的代码路径,那么结构化绑定可能更有意义。


在其他语言中,打包和拆包更简单。以 JavaScript 为例,其中数组可以是以太源的;打包更多的东西只是意味着将它们包含在一个以 - 分隔的列表中。对于开箱,有操作员。下面是本机 JavaScript 代码,对应于上面的 C++ 代码,它使用了一个完整的库:,[]...

add = x => x[0] + x[1] + x[2]
console.log(add([1, 2, 3])) // prints 6
add = (x, y, z) => x + y + z;
console.log(add(...[1, 2, 3])) // prints 6


最后,在像 Haskell 这样的语言中,函数都是 curried,即它们一个接一个地接受参数,打包和解包分别与 uncurrying 和 currying 基本一致:

add3'curried = \x y z -> x + y + z -- === curry3 add3'uncurried
triple = (1, 2, 3)
uncurry3 add3'curried $ triple -- prints 6

add3'uncurried = \(x, y, z) -> x + y + z -- === uncurry3 add3'curried
curry3 add3'uncurried 1 2 3 -- prints 6

评论

0赞 Enlico 8/18/2023
500分消失了,只是因为我推迟了回答问题:'(