C++17 解构绑定

Posted 石中火本火

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++17 解构绑定相关的知识,希望对你有一定的参考价值。

在python中,加入我们有一个函数返回了两个数值,如:

def getData(x, y):
	return x,y

那么我们在使用这个函数时只需要使用两个新变量去接收函数返回值就可以:

a,b = getData(4, 5)

但是对于C++来说就没有这么方便了,比如一个函数要返回多个数通常会把他们封装成一个pair或者vector容器或者自定义结构体返回,在接收时也需要使用同样的类型去接收,然后再做出处理。

C++17有一个新特性极大方便了简化了此类操作,这个特性就是解构绑定,即一次性的做到像python那样直接使用返回的变量。

如下代码:

struct MyStruct 
    int x;
    double y;
;

MyStruct myFunc() 
    return 42, 3.14;


int main() 
    MyStruct s = myFunc();
    int x = s.x;
    double y = s.y;
    // ...

可以使用解构绑定简化为:

auto [x, y] = myFunc();

auto会自动推导出类型。

但是有时候我们需要将解构的变量绑定到提前已经定义好的变量上怎么办呢?

我们不能像普通变量那样直接去掉auto,也不能在这句代码之前先定义好两个同名变量,这样会导致变量的同名错误。

有另一个关键字支持这样的操作:

int x=1,y=2;
std::tie(x, y) = myFunc();
std::tie(std::ignore, y) = myFunc();

如上代码所示,tie关键字即可完成绑定至已定义变量的功能,或者也可以使用ignore来忽视该位置变量,对等于python中的_(下划线)。

你可以在 Typescript 函数中有可选的解构参数吗?

【中文标题】你可以在 Typescript 函数中有可选的解构参数吗?【英文标题】:Can you have optional destructured arguments in a Typescript function? 【发布时间】:2019-03-21 10:38:02 【问题描述】:

我想编写一个函数,它接受一个对象参数,在函数签名中使用解构,并且该参数是可选的:

myFunction(opt1, opt2?: opt1?: boolean, opt2?: boolean)

但是,Typescript 不允许(“绑定模式参数在实现签名中不能是可选的。”)。

不解构当然可以:

myFunction(options?: opt1?: boolean, opt2?: boolean) 
  const opt1 = options.opt1;
  const opt2 = options.opt1;
  ...

好像这些应该是一样的,但是上面的例子是不允许的。

我想使用一种解构语法 (1) 因为它存在,而且是一种很好的语法,而且上面的两个函数的行为应该是一样的,并且 (2) 因为我也想要一种简洁的方式指定默认值:

myFunction(opt1, opt2 = true?: opt1?: boolean, opt2?: boolean)

如果不进行解构,我必须将这些默认值隐藏在函数的实现中,或者有一个实际上是带有构造函数的某个类的参数......

【问题讨论】:

【参考方案1】:

改用默认参数:

function myFunction( opt1, opt2 = true :  opt1?: boolean; opt2?: boolean;  = ) 
    console.log(opt2);


myFunction(); // outputs: true

为了不破坏undefined是必要的:

function myFunction( opt1, opt2 ) 

    
// Uncaught TypeError: Cannot destructure property `opt1` of 'undefined' or 'null'.
myFunction();

【讨论】:

有没有办法避免参数对象中opt1opt2 的重复?类似function myFunction( opt1?: boolean; opt2?: boolean = false; = ) @icl7126 不幸的是没有。通常在这些情况下我会将内联类型提取到接口中,因为它太冗长了:( ...和there's no easy way to define default interface property values。【参考方案2】:

如果没有作为参数给出的对象,则不能解构。因此,如前一篇文章所述,在 parmas 中使用默认对象:

type Options =  opt1?: boolean; opt2?: boolean; 

function myFunction( opt1, opt2 : Options = ) 
    console.log(opt2, opt1);


myFunction() // undefined,  undefined 
myFunction(opt1: false); // undefined,  false 
myFunction(opt2: true); // true,  undefined

我想补充的是,当满足以下 2 个条件时,参数中的这种解构模式会增加最大的价值:

选项的数量可能会发生变化 函数的 API 可能会发生变化。即函数参数可能会改变

基本上解构为您提供了更大的灵活性,因为您可以添加任意数量的选项,而只需对函数的 API 进行最少的更改。

但是,更基本的版本会更简单:

// If the function is not likely to change often just keep it basic:
function myFunctionBasic( opt1? :boolean, opt2?: boolean ) 
    console.log(opt2, opt1);

【讨论】:

这个答案是唯一为我解决问题的答案(使用函数重载)【参考方案3】:

如果您想混合可选参数和必需参数但有一个所有值都是必需/非空的导出类型,这是最好的方法:

export function newCar(args: 
    year?: number
    make?: string
    model: string
    owner: [string, string]
) 
    const defaults = 
        year: 1999,
        make: "toyota",
    
    return  ...defaults, ...args 
    // to get a Readonly<Car>:
    // return Object.freeze(args)


export type Car = ReturnType<typeof newCar>

const c = newCar( model: "corolla", owner: ["Gorg", "Blafson"] )

export function print(c: Car) 
    console.log(`$c.owner's gorgeous $c.year $c.model from $c.make`)

【讨论】:

以上是关于C++17 解构绑定的主要内容,如果未能解决你的问题,请参考以下文章

Rust语言圣经07 - 变量绑定与解构

字典中的 foreach 解构

Rust学习教程07 - 变量绑定与解构

03JavaScript程序设计修炼之道 2019-06-04_fe-js-044es6解构赋值之数组解构_2019-06-06_20-10-17 解构赋值数组排序法

C++新特性C++17结构化绑定

es6 变量的解构赋值