reduce() vs. reduce(into:)

`reduce(_:_:)``reduce(into:_:)`

  • ๅƒๆ•ธไธๅŒ๏ผš reduce(into:_:)ๆœ‰ inout parameter๏ผŒreduce(_:_:)ๆฒ’ๆœ‰๏ผŒๆ‰€ไปฅ็•ถๅฎƒๅฐ‡ไน‹ๅ‰็ดฏ็ฉ็š„็ตๆžœๅ‚ณๅ…ฅ nextPartialResult ไธฆ้œ€่ฆๆ›ดๆ–ฐๆ–ฐ็š„็ดฏ็ฉ็ตๆžœๆ™‚๏ผŒๅฐฑๅฟ…้ ˆ่ค‡่ฃฝ (copy-on-write) ไน‹ๅ‰็š„็ตๆžœ๏ผŒๆ‰€ไปฅๅฆ‚ๆžœ Result ๆ˜ฏไธ€ๅ€‹ๅคงๅž‹็š„ Array ๆˆ– Dictionary ไน‹้กž็š„ๅž‹ๅˆฅ๏ผŒๅฐฑๆœƒๅฐ็จ‹ๅผ็š„ๆ•ˆ็Ž‡็”ข็”Ÿ่กๆ“Šใ€‚

  • ๅ›žๅ‚ณๆ–นๅผไธๅŒ๏ผš

    reduce(_:_:) ๆ˜ฏๅฐ‡ nextPartialResult ๆœ€ๅพŒ็š„ return value ไฝœ็‚บๆ•ดๅ€‹ๆ–นๆณ•็š„ๅ›žๅ‚ณๅ€ผใ€‚reduce(into:_:) ๅ‰‡ๆ˜ฏ็”จ updateAccumulatingResult ๆŒ็บŒๅฐ partialResult ๅšๆ›ดๆ–ฐ๏ผŒ็„ถๅพŒไปฅ partialResult ๆœ€ๅพŒ็š„ๅ€ผไฝœ็‚บๅ›žๅ‚ณๅ€ผใ€‚

ๆ‰€ไปฅไฝฟ็”จreduce(into:_:)ๆ™‚่ฆๆณจๆ„๏ผšใ€Œไธ€ๅฎš่ฆ้€้Ž updateAccumulatingResult ไพ†ๆ›ดๆ–ฐ partialResultใ€๏ผŒๅฆๅ‰‡ๅ›žๅ‚ณๅ€ผๆœƒๆ˜ฏๅŽŸไพ†็š„ initialResultโ—

// `reduce(_:_:)`
func reduce<Result>(
    _ initialResult    : Result, 
    // โญ๏ธ combine function (with return value)
    _ nextPartialResult: (Result, Element) throws -> Result
) rethrows -> Result

// `reduce(into:_:)`
func reduce<Result>(
    into initialResult: Result, 
    _ updateAccumulatingResult: (
        _ partialResult: inout Result,    // โญ๏ธ inout parameter
        Self.Element    
    ) throws -> ()                        // โญ๏ธ no return value
) rethrows -> Result

.reduce(into:) is preferred over reduce() for efficiency when the result is a copy-on-write type, for example an Array or a Dictionary. ๐Ÿ‘‰ .reduce(into:_:)

Example

ๆˆ‘ๅ€‘็”จๅˆไฝต SwiftUI ไธญ็š„ transitions ไพ†่ˆ‰ไพ‹๏ผŒ่ชชๆ˜Ž้€™ๅ…ฉ่€…็š„็”จๆณ•ๆœ‰ๅ“ชไบ›ไธๅŒใ€‚ๅœจๅˆไฝต SwiftUI ไธญ็š„ transitions ๆ™‚๏ผŒไฝฟ็”จ SwiftUI ๅŽŸๆœ‰็š„่ชžๆณ•๏ผŒ้กฏๅพ—ๅคช้Žๅ†—้•ท๏ผš

AnyTransition
    .move(edge: .leading)
    .combined(with: .opacity)
    .combined(with: .scale)

่‹ฅไฝฟ็”จ .reduce() ๆˆ– .reduce(into:)๏ผŒๅ‰‡ๅฏไปฅๅฐ‡่ชžๆณ•่ฎŠ็‚บๆ›ด็ฒพ็ฐก๏ผš

// ็„กๆณ•่‡ช่กŒๆŽจๆ–ท (infer) AnyTransition ๅž‹ๅˆฅ็š„ๆ™‚ๅ€™๏ผš
AnyTransition(.move(edge: .leading), .opacity, .scale)

// ๅฏไปฅ่‡ช่กŒๆŽจๆ–ท AnyTransition ๅž‹ๅˆฅ็š„ๆ™‚ๅ€™๏ผš
.combined(.move(edge: .leading), .opacity, .scale)

ๅ‰ๆๆ˜ฏ่ฆๅ…ˆๅŠ ๅ…ฅไปฅไธ‹็š„ extension๏ผš

extension AnyTransition {
    
    // โญ๏ธ combining transitions
    // AnyTransition([.scale, .opacity, ...]) ........ (1)
    init(_ transitions: [AnyTransition]) {
        // use reduce() or reduce(into:)
    }
    
    // ่ฎ“ๅฏไปฅไฝฟ็”จ็š„่ชžๆณ•ๆ›ด่ฑๅฏŒ๏ผŒๅœจๅฏไปฅไฝฟ็”จ AnyTransition ็š„ๅœฐๆ–น๏ผŒ็›ดๆŽฅ็”จ๏ผš
    // .combined(.move, .scale, ...)
    public static func combined(_ transitions: AnyTransition...) -> AnyTransition {
        .init(transitions)
    }
}

extension AnyTransition: ExpressibleByArrayLiteral {
    // convenience init
    // AnyTransition(.move, .scale, .opacity, ...)
    public init(arrayLiteral elements: AnyTransition...) {
        self.init(elements)    // ไฝฟ็”จ (1)
    }
}

่‡ณๆ–ผ็”จ .reduce() ้‚„ๆ˜ฏ .reduce(into:)๏ผŸๅฎƒๅ€‘ไน‹้–“ๆœ‰ไฝ•ไธๅŒ๏ผŒ่ซ‹็œ‹ไธ‹้ข็š„็จ‹ๅผ็ขผ๏ผš

.reduce()

init(_ transitions: [AnyTransition]) {
    let intialValue = AnyTransition.identity
    // โญ๏ธ ไฝฟ็”จ `reduce(_:_)`
    self = transitions.reduce(intialValue) { (result, transition) in
        // โญ๏ธ ไธ‹้ข็š„็ตๆžœๆœƒใ€Œ่‡ชๅ‹•ๆˆ็‚บๆ–ฐ็š„ `result`ใ€๏ผŒไธ้œ€ๆ‰‹ๅ‹•ๆ”นๅฏซ `result`
        //    ๆ‰€ไปฅๅฎ˜ๆ–น็จฑ้€™ๅ€‹้ƒจๅˆ†็š„ closure ็‚บ๏ผš`nextPartialResult`ใ€‚
        result.combined(with: transition)    // โญ๏ธ implicit return
    }
}

.reduce(into:)

init(_ transitions: [AnyTransition]) {
    var intialValue = AnyTransition.identity
    // โญ๏ธ ไฝฟ็”จ `reduce(into:_:)`
    self = transitions.reduce(into: intialValue) { (result, transition) in
        // โญ๏ธ ่จ˜ๅพ—ๆ‰‹ๅ‹•ๆ”นๅฏซ `result` ่ฎŠๆ•ธ๏ผŒๅฆๅ‰‡ๆ•ˆๆžœไธฆไธๆœƒ็ดฏๅŠ ใ€‚
        //    ๅ› ็‚บๅฆ‚ๆžœๆˆ‘ๅ€‘ไธๅฏซ `result = ...`๏ผŒ้€™ๆ™‚ `result` ่ฎŠๆ•ธ
        //    ไธฆไธๆœƒ่‡ชๅ‹•ๆ”น่ฎŠ๏ผŒๆ‰€ไปฅๅฎ˜ๆ–น็จฑ้€™ๅ€‹้ƒจๅˆ†็‚บ `updateAccumulatingResult`
        //    ่€Œไธๆ˜ฏ `nextPartialResult`ใ€‚
        result = result.combined(with: transition)    // โญ๏ธ no return value
    }
}

Last updated