Swift:用于更新字典值的自定义运算符

Swift:用于更新字典值的自定义运算符,swift,custom-operator,Swift,Custom Operator,是否有一种优雅的方法来生成更新字典值的自定义运算符 更具体地说,我需要一个前缀运算符,它递增与给定键对应的整数值: prefix operator +> {} prefix func +> //Signature { ... } var d = ["first" : 10 , "second" : 33] +>d["second"] // should update d to ["first" : 10 , "second" : 34] 这是可行的使用功能的方式

是否有一种优雅的方法来生成更新字典值的自定义运算符

更具体地说,我需要一个前缀运算符,它递增与给定键对应的整数值:

prefix operator +> {}

prefix func +> //Signature 
{
    ...
}

var d = ["first" : 10 , "second" : 33]
+>d["second"] // should update d to ["first" : 10 , "second" : 34]
这是可行的使用功能的方式。例如,要计算阵列中元素的频率,请执行以下操作:

func update<K,V>(var dictionary: [K:V], key: K, value: V) -> [K:V] {
    dictionary[key] = value
    return dictionary
}

func increment<T>(dictionary: [T:Int], key: T) -> [T:Int] {
    return update(dictionary, key: key, value: dictionary[key].map{$0 + 1} ?? 1)
}

func histogram<T>( s: [T]) -> [T:Int] {
    return s.reduce([T:Int](), combine: increment)
}

let foo = histogram([1,4,3,1,4,1,1,2,3]) // [2: 1, 3: 2, 1: 4, 4: 2]
func更新(变量字典:[K:V],键:K,值:V)->[K:V]{
字典[键]=值
返回字典
}
函数增量(字典:[T:Int],键:T)->[T:Int]{
返回更新(dictionary,key:key,value:dictionary[key].map{$0+1}??1)
}
func直方图(s:[T])->[T:Int]{
返回s.reduce([T:Int](),combine:increment)
}
设foo=直方图([1,4,3,1,4,1,1,2,3])/[2:1,3:2,1:4,4:2]
但我正试图用一个自定义操作符做同样的事情

var d = ["first" : 10 , "second" : 33]

d["second"]?++
操作员可以这样实现:

prefix operator +> {}
prefix func +> <I : ForwardIndexType>(inout i: I?) {
  i?._successorInPlace()
}

var dict = ["a":1, "b":2]

+>dict["b"]

dict // ["b": 3, "a": 1]
:

或者,使用未记录的函数:

extension SequenceType where Generator.Element : Hashable {
  func frequencies() -> [Generator.Element:Int] {
    var result: [Generator.Element:Int] = [:]
    for el in self {result[el]?._successorInPlace() ?? {result[el] = 1}()}
    return result
  }
}
prefix operator +> {}
prefix func +>(inout n: Int) {
    n++
}

这可能比您想要的要难看一点,但您可以在通用重载运算符中使用不安全的可变指针来完成:

prefix operator +> {}

prefix func +><T>( value:UnsafeMutablePointer<T?> )
{
    print( value.memory )
    if let intValue = value.memory as? Int {
        value.memory = (intValue + 1) as? T
    }
}

var d = ["first" : 10 , "second" : 33]
print( d["second"] ) // Optional(33)
+>(&d["second"])
print( d["second"] ) // Optional(34)
前缀运算符+>{}
前缀func+>(值:UnsafeMutablePointer)
{
打印(value.memory)
如果让intValue=value.memory为?Int{
value.memory=(intValue+1)为?T
}
}
变量d=[“第一”:10,“第二”:33]
打印(d[“秒])//可选(33)
+>(&d[“第二”])
打印(d[“秒])//可选(34)

首先,寻找一种使用函数(而不是自定义运算符)的方法。您需要一个函数,该函数引用一个项(来自字典)并更新其值。。。这需要一个
inout
参数类型

func increment(inout n: Int) {
    n++
}

var d = ["first" : 10 , "second" : 33]
increment(&d["first"]!)
print(d) // -> "[first: 11, second: 33]"
您不必关心字典中的值-
inout
接受任何类型的引用并直接更新它。(这甚至适用于计算属性。您可以传递一个
inout
,它将在读取和写入值时正确地通过setter和getter。)并且因为您不必关心字典,您实际上不需要泛型-如果您想要一个在
Int
的字典上工作的函数,只需创建一个在
Int
s上工作的函数,然后让
inout
完成其余的工作

现在,自定义运算符只是函数,因此请为函数创建一个运算符:

extension SequenceType where Generator.Element : Hashable {
  func frequencies() -> [Generator.Element:Int] {
    var result: [Generator.Element:Int] = [:]
    for el in self {result[el]?._successorInPlace() ?? {result[el] = 1}()}
    return result
  }
}
prefix operator +> {}
prefix func +>(inout n: Int) {
    n++
}
但是,您不能完全使用您要求的语法来调用它:字典查找总是导致可选类型,因此您必须展开

+>d["second"]  // error
+>d["second"]! // but this works — operators automatically make params inout as needed
print(d) // -> "[first: 11, second: 34]"

你的
++>
++
做的事情几乎完全一样,不是吗?我是说,
++d[“秒”]效果很好。不过,对我来说,强制展开会扼杀它。相反,我会这样做:
prefix func++>(inout n:Int?{n?++}
@oisdk是的,但OP显然询问了一个自定义运算符定义,一般来说,
++>
的主体不一定要执行增量。正是这条推特让我来到这里。。也许只是xcode beta 4有一个bug,不知道如何处理
++
操作。我忘记了
inout
,我也喜欢rickster的答案。