Swift: Reduce Function with a closure

Swift: Reduce Function with a closure

下面是我难以理解的代码:

  let rectToDisplay = self.treasures.reduce(MKMapRectNull)  { //1
    (mapRect: MKMapRect, treasure: Treasure) -> MKMapRect in //2

     let treasurePointRect = MKMapRect(origin: treasure.location.mapPoint, size: MKMapSize(width: 0, height: 0)) //3

       return MKMapRectUnion(mapRect, treasurePointRect)
    }

我对reduce函数的理解是:

var people [] // an array of objects
var ageSum = 0
ageSum = people.reduce(0) { [=12=] + .age}

//(0) = initial value
//[=12=] = running total
// = an object in an array

我对闭包的理解是:

{ (params) -> returnType in
  statements
}

我对上面代码的理解是:

//1 = reduce 函数的初始值设置为 (MKMapRectNull)

//2 = 不是 运行 总和数组中的对象,而是传入一个带有两个参数的闭包 returns a MKMapRect:

(mapRect: MKMapRect, treasure: Treasure) -> MKMapRect 

//3 = 这就是我卡住的地方。使用两个参数 origin: treasure.location.mapPointsize: MKMapSize(width: 0, height: 0)

调用结构 MKMapRect

问题一:如果传入的值为0,0MKMapSize如何计算?它是如何获取后续值并添加它们的?

问题2:当这一行返回到//2 closurereturn MKMapRectUnion(mapRect, treasurePointRect)它是如何变成运行总数的,它是如何知道的到达 self.treasures 的下一个元素 ?

答案 2:

第二次(第三次、第四次)调用闭包的第一个参数是前一次调用闭包的result输出。唯一的例外是第一个调用,它没有以前的调用可以继承,这就是为什么 reduce 将值 0 作为第二个参数——这是一个特殊的值,可以输入到第一个调用中。

让我们想象以下场景 - 您有一个数字数组:

let a = [1,2,3]

并且您想使用 reduce 求和:

let sum = reduce(a,0) { (accumulator, nextValue) in accumulator + nextValue }

那么让我们看看每次调用会发生什么:

call#    acc    next    result
1        0      1       0+1 -> 1       # the zero is from reduce's second arg
2        1      2       1+2 -> 3       # the 1 is from the previous result
3        3      3       3+3 -> 6

现在我们有 运行 个元素要处理,所以我们 return 最终值 6,这确实是 1,2 和 3

的总和

让我们想象一个稍微复杂的场景——将一系列格式化的数字值添加到一个字符串中。这是减少:

let sum = reduce(a,"") { (accumulator, nextValue) in accumulator + nextValue }

看起来几乎相同,但您会注意到 initial 设置为 "" 而不是 0。运算符 + 现在组合了一个 String 和一个 Int。

call#    acc    next    result
1        ""      1      ""+1 -> "1"
2        "1"     2      "1"+2 -> "12"
3        "12"    3      "12"+3 -> "123"

我们完成了,可以打印出字符串,或其他任何东西。


现在来看你的第一个问题!

将一系列点添加到地图类似于(但不完全相同)将数字相加;它更接近字符串示例,其中累加器具有与数组元素(integer/treasure 位置)不同的类型(string/map)。

您当然可以将 "castle grey skull' to an empty map, and then add "shady cove" 添加到上面有灰色骷髅头的地图,然后将 'treasure location' 添加到已经有 "castle grey skull" 和 "shady cove" 的地图画上去,大功告成,可以开始寻宝了。

您的初始值不是零(或“”),而是空映射。

添加新点(矩形)时,它被添加到具有前一个点的地图,而不是直接添加到前一个点。

之前的点留在地图上,没有变化!它只是在附近有一个新的地图标记,可以与之分享故事。

关于你的问题,即大小为零的矩形如何做任何事情,我认为这与点相同。

如果从命令式的角度考虑 reduce 有帮助,那么这实际上就是您的代码正在做的事情:

var rectToDisplay = MKMapRectNull
for treasure in self.treasures {
    let treasurePointRect = MKMapRect(origin: treasure.location.mapPoint, size: MKMapSize(width: 0, height: 0))
    rectToDisplay = MKMapRectUnion(rectToDisplay, treasurePointRect)
}