Lambda表达式中引用变量的问题

Lambda表达式中引用变量的问题

Lambda表达式内部自定义的变量肯定没问题。引用的外部final变量也没问题。问题在于effectively final变量的理解,及应用场景的认识。引用的外部变量没有加final限定符,只要没有发生过改变,就可以当作是事实上的final变量。变量没改变过,就是说Lambda表达式引用的外部变量在它所在的作用域范围内,只赋值过一次**,该变量名称只出现过一次**,就算是effectively final。举例说明。
例1:增强for循环,实质上使用的是迭代器(参见例3)。

String[] array = {"a", "b", "c"};
        for(Integer i : Arrays.asList(1,2,3)){
            Stream.of(array).map(item -> Strings.padEnd(item, i, '@'))
                    .forEach(System.out::println);
        }

在例1中,虽然for循环代码块中变量 i 的值是变化的,但是 i 只出现过一次,没有明显的改变,也算事实上的final,Lambda表达式能通过。与之相反的示例,看例2。
例2:普通for循环。

 String[] array = {"a", "b", "c"};
        for(Integer i = 1; i<4; i++){
            Stream.of(array).map(item -> Strings.padEnd(item, i, '@'))
                    .forEach(System.out::println);
        }

在例2中,Lambda表达式引用的外部变量 i 所在的作用域范围是for循环体。明显有两次赋值 i =1 , i++。要报错误提示:Variable used in lambda expression should be final or effectively final。变量 i 不能算是effectively final。

例3:迭代器。

String[] array = {"a", "b", "c"};
        List<Integer> list = Arrays.asList(1, 2, 3);
        Iterator<Integer> iterator = list.iterator();
        while(iterator.hasNext() ){
            int i = iterator.next();
            Stream.of(array).map(item -> Strings.padEnd(item, i, '@'))
                    .forEach(System.out::println);
        }

增加for循环也会转为迭代器调用模式。可以明显看出变量 i 只出现过一次有效赋值,没有修改过,算是effectively final。Lambda表达式能通过。

例4: 将普通for循环变量赋给一个中间变量,可通过。

 String[] array = {"a", "b", "c"};
        for(Integer i = 1; i<4; i++){
            int k = i;
            Stream.of(array).map(item -> Strings.padEnd(item, k, '@'))
                    .forEach(System.out::println);
        }

因为变量 k 的作用域是for循环的一次{},变量 k 在一次{}代码块中只赋值过一次后,没有再被改变过,即effectively final。Lambda表达式能通过。再举两个很近似的例子,就更能说明问题。
例4-2: 变量的判断不算是被修改。

 String[] array = {"a", "b", "c"};
        for(Integer i = 1; i<4; i++){
            int k = i;
            if(k>2){
                System.out.println(k);
            }
            Stream.of(array).map(item -> Strings.padEnd(item, k, '@'))
                    .forEach(System.out::println);
        }

该Lambda表达式能通过。因为 k 只有过一次赋值修改后就没有改变过。k 的后两次出现只是读取使用,不是写入。

例4-3: 自己赋给自己也算是再次被修改。

 String[] array = {"a", "b", "c"};
        for(Integer i = 1; i<4; i++){
            int k = i;
            k = k;
            Stream.of(array).map(item -> Strings.padEnd(item, k, '@'))
                    .forEach(System.out::println);
        }

这个Lambda表达式也会报错。因为变量 k 出现了两次赋值,不符合final的定义。这样多举几个例子测试,就算彻底搞明白了effectively final的含义及应用场景了。

在Qt中,lambda表达式可以引用变量,通过捕获列表来控制对外部变量的访问。默认情况下,lambda表达式按值捕获外部变量,即复制一份外部变量的值。这意味着,lambda表达式无法修改通过复制方式捕获的外部变量。如果希望修改这些变量,我们需要使用引用方式进行捕获。例如,使用"[&]"来按引用捕获所有外部变量。然后在lambda表达式中,可以直接修改这些变量的值。 使用lambda表达式引用变量的一个重要注意事项是延迟调用。在lambda表达式定义之后,如果外部变量发生了修改,lambda表达式仍然会使用最初捕获到的变量值。例如,如果按值捕获了一个外部变量,然后修改了这个变量的值,lambda表达式仍然会使用最初捕获到的值。 需要注意的是,lambda表达式的语法形式可简单归纳如下: ``` [capture list](parameters) -> return type { body } ``` 其中,捕获列表用于指定需要捕获的外部变量,参数列表和返回类型用于指定lambda表达式的参数和返回值类型,以及函数体用于实现具体的功能。 在Qt中,lambda表达式可以方便地定义和使用函数对象。捕获的外部变量将成为lambda表达式的成员变量,并可以在函数体中访问。值得注意的是,没有捕获变量lambda表达式可以直接转换为函数指针,而捕获变量lambda表达式则不能转换为函数指针。 总结起来,Qt中的lambda表达式可以引用变量,并通过捕获列表来控制对外部变量的访问。可以按值或按引用捕获外部变量,并在lambda表达式中访问和修改这些变量的值。使用lambda表达式可以方便地定义和使用函数对象。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值