swift 仅当右侧不为空时执行赋值

klr1opcd  于 2023-09-30  发布在  Swift
关注(0)|答案(7)|浏览(129)

是否有可能仅执行一项分配(例如:一个非可选的属性),如果右手边不是nil?我正在寻找一个单行形式:

if let unwrapped = funcThatReturnsOptional() {
    object.nonOptionalProperty = unwrapped
}
amrnrhlw

amrnrhlw1#

与您的代码具有相同效果的单个表达式是

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

但你的代码可读性肯定更好。
这里使用了Optionalmap()方法,并且只有当函数不返回nil时才会执行闭包。

hwazgwia

hwazgwia2#

有很多种方法都不是很难操作
使用??:

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

使用函数:

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

setNotNil(&object.nonOptionalProperty, funcThatReturnsOptional())

使用运算符:

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

object.nonOptionalProperty <-?? funcThatReturnsOptional()

使用扩展:

extension Equatable
{ mutating func setNotNil(value:Self?) { if value != nil { self = value! } } }

object.nonOptionalProperty.setNotNil(funcThatReturnsOptional())
pxyaymoc

pxyaymoc3#

好的,实际上有一种方法可以通过引入一个新的运算符?=来实现这一点:

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

通过使用上面定义的?=,如果可选的内部有一个值,实际上可以将可选的分配给非可选的。

ijnw1ujt

ijnw1ujt4#

来自@Sajjon的答案可以通过使用if let来避免反射来改进。

precedencegroup OptionalAssignment { associativity: right }

infix operator ?= : OptionalAssignment

public func ?= <T>(variable: inout T, value: T?) {
    if let value = value {
        variable = value
    }
}
qhhrdooz

qhhrdooz5#

@ch1llb4y和@ tyler-sheffer提供的解决方案都不起作用,因为泛型丢失了关于可选值的信息。但这可以使用下面的unwrap方法修复。

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
}

我还没有想出一个解决方案,不必在unwrap(any: value) ?? nil中写入?? nil

pw9qyyiw

pw9qyyiw6#

我更喜欢用这样的闭包来完成它:

let unwrapped = { funcThatReturnsOptional() ?? object.nonOptionalProperty }()

这样,你也可以在处理多个可选属性时使用it guard语句:

guard let unwrapped = { funcThatReturnsOptional() ?? object.OptionalProperty }() else { return }
fumotvh3

fumotvh37#

由于Swift是关于协议的,而POP,涉及协议的解决方案必然会发生。
这里有一个古怪的协议,允许您将可选值分配给非可选属性:

protocol OptionalShortcut { }

extension OptionalShortcut {
    subscript<T>(_ keyPath: WritableKeyPath<Self,T>) -> T? {
        get { self[keyPath: keyPath] }
        set { if let newValue = newValue { self[keyPath: keyPath] = newValue } }
    }
}

只要让你的class/struct/enum/actor符合上面的协议,你就可以像这样写赋值:

object[\.nonOptionalProperty] = funcThatReturnsOptional()

我个人不喜欢下标和键路径语法(方括号很难看,除非它们涉及集合),但为了完整起见,我想给予解决方案。

相关问题