You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Supply与普通Array中map函数处理Empty值的行为是否不一致?

Supply与Array中map处理Empty值的行为差异

近期我在学习Swift的Combine框架,苹果官方说明:

Combine框架为应用处理事件提供了声明式方法。无需实现多个委托回调或完成处理闭包,即可为指定事件源创建单一处理链,链中每个环节都是Combine操作符,对前一步接收的元素执行特定操作。

Combine中有一个compactMap函数,可过滤nil值,示例代码如下:

import Combine

let strings = ["a", "1.24", "3", "def", "45", "0.23"].publisher

strings
  .compactMap { Float($0) }
  .sink(receiveValue: {
    print($0)
  })
  .store(in: &subscriptions)

我将上述代码用Raku改写后,发现运行结果不符合预期:

my @strings = ["a", "1.24", "3", "def", "45", "0.23"];
my Supply $supply = Supply.from-list(@strings);
my Supply $compact = $supply.map(-> $value {
  try { Num($value) }
  if $! { Empty } else { Num($value) }
 }); # .grep(Num);

$compact.tap(
    &say,
    done => { say 'finished' },
    quit => { say 'done'     }
);

# 输出:
# ()
# 1.24
# 3
# ()
# 45
# 0.23

但在普通Array上使用map处理Empty值时,Empty会被自动过滤:

my @strings = ["a", "1.24", "3", "def", "45", "0.23"];

my @compacted = @strings.map(-> $value {
    try { Num($value) }
    if $! { Empty } else { Num($value) }
});

.say for @compacted;

# 输出:
# 1.24
# 3
# 45
# 0.23

结论:行为确实不一致

Array的map会自动展开Iterable类型的返回值(包括Empty),当返回Empty时,相当于当前元素被过滤,不会加入结果数组。

而Supply的map是将每个返回值直接作为事件发送,Empty在Supply中会被解析为空元组()并发送出去,不会被过滤。

正确实现Combine compactMap的Raku写法

要在Supply中实现类似compactMap的过滤效果,可以使用flat-map替代map:

my @strings = ["a", "1.24", "3", "def", "45", "0.23"];
my Supply $supply = Supply.from-list(@strings);
my Supply $compact = $supply.flat-map(-> $value {
  try { Num($value) }
  if $! { Empty } else { Num($value) }
});

$compact.tap(
    &say,
    done => { say 'finished' },
    quit => { say 'done'     }
);

# 输出:
# 1.24
# 3
# 45
# 0.23
# finished

flat-map会将返回的Iterable(比如Empty、列表)展开为单个事件,Empty不会产生任何事件,从而达到过滤无效值的效果,和Array的map行为一致。

也可以先转换值再过滤:

my @strings = ["a", "1.24", "3", "def", "45", "0.23"];
my Supply $supply = Supply.from-list(@strings);
my Supply $compact = $supply.map(-> $value { try Num($value) })
                           .grep(-> $val { $val.defined && $val ~~ Num });

$compact.tap(
    &say,
    done => { say 'finished' },
    quit => { say 'done'     }
);

内容的提问来源于stack exchange,提问作者chenyf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 19:39:44