Perform assignment only if right side is not nil

后端 未结 5 1623
不思量自难忘°
不思量自难忘° 2020-12-06 05:35

Is there a possibility to only perform an assignment (e.g. to a non-optional property) if the right hand side is not nil? I am looking for a one-line form for:



        
相关标签:
5条回答
  • 2020-12-06 06:08

    A single expression with the same effect as your code is

    funcThatReturnsOptional().map { object.nonOptionalProperty = $0 }
    

    but your code is definitely better readable.

    Here the map() method of Optional is used and the closure is executed only if the function does not return nil.

    0 讨论(0)
  • 2020-12-06 06:11

    There are various ways that aren't too unwieldy

    Using ?? :

    object.nonOptionalProperty = funcThatReturnsOptional() ?? object.nonOptionalProperty 
    

    Using a function :

    func setNotNil<T>(inout variable:T, _ value:T?)
    { if value != nil { variable = value! } }
    
    setNotNil(&object.nonOptionalProperty, funcThatReturnsOptional())
    

    Using an operator :

    infix operator <-?? { associativity right precedence 90 assignment }
    func <-??<T>(inout variable:T, value:T?)
    { if value != nil { variable = value! } }
    
    object.nonOptionalProperty <-?? funcThatReturnsOptional() 
    

    Using an extension :

    extension Equatable
    { mutating func setNotNil(value:Self?) { if value != nil { self = value! } } }
    
    object.nonOptionalProperty.setNotNil(funcThatReturnsOptional())
    
    0 讨论(0)
  • 2020-12-06 06:11

    The answer from @Sajjon could be improved by using an if let to avoid reflection.

    precedencegroup OptionalAssignment { associativity: right }
    
    infix operator ?= : OptionalAssignment
    
    public func ?= <T>(variable: inout T, value: T?) {
        if let value = value {
            variable = value
        }
    }
    
    
    0 讨论(0)
  • 2020-12-06 06:16

    Neither the solution provided by @ch1llb4y nor by @tyler-sheaffer works since generics loses information about optional values. But this can be fixed using the unwrap method below.

    precedencegroup OptionalAssignment {
        associativity: right
    }
    
    infix operator ?= : OptionalAssignment
    
    public func ?= <T>(variable: inout T, value: T?) {
        if let unwrapped = unwrap(any: value) ?? nil {
            variable = unwrapped
        }
    }
    
    public func unwrap<T: Any>(any: T) -> T? {
        let mirror = Mirror(reflecting: any)
        guard mirror.displayStyle == .optional else { return any }
        guard let child = mirror.children.first else { return nil }
        return unwrap(any: child.value) as? T
    }
    

    I have not yet come up with a solution for not having to write ?? nil in unwrap(any: value) ?? nil though.

    0 讨论(0)
  • 2020-12-06 06:20

    Okay, actually there is a way to achieve exactly this by introducing a new operator ?=:

    infix operator ?= { associativity right precedence 90 }
    func ?= <T: Any> (inout left: T, right: T?) {
        if let right = right {
            left = right
        }
    }
    

    By using ?= defined as above you can actually assign an optional to a non-optional if the optional has a value inside.

    0 讨论(0)
提交回复
热议问题