如何一般地处理枚举(集合)的数组和字典的不同返回类型?

时间:2014-07-14 20:48:28

标签: arrays generics dictionary swift each

作为一个练习练习,作为一个练习练习,我正在尝试写一个等同于下划线的快照.js' _.each

_.each({foo: true, bar: false}, function(value, key) {...}
_.each([true, false], function(value, key) {...}

但由于枚举(集合)为字典和数组返回不同类型的结果,因此证明是困难的:

for (indexInt, (key, value)) enumerate(["foo": true]) {...}
for (key, value) enumerate([true]) {...}

如何在不明确检查ArrayDictionary的通用集合类的情况下处理这两种不同的返回类型?

返回类型检查将失败,因为以下两个示例应区别对待,但从enumerate()返回等效类型:

for (indexInt, (key, value)) enumerate(["foo": true]) {...}
for (indexInt, (key, value)) enumerate([("foo", true")]) {...}

此外,FWIW,$ .swift似乎对此表示不满:

https://github.com/ankurp/Dollar.swift/blob/master/Dollar/Dollar/Dollar.swift#L193-L217

编辑:格式化。还.. ..

破碎的通用实施

func each<C: Collection>(collection: C, fn: (Any, Any) -> ()) -> C {
    // On next line... Error: Tuple pattern cannot match values of the non-tuple type 'C.GeneratorType.Element'
    for (_, (k, v)) in enumerate(collection) {
        if let innerV = collection[innerK] {
            fn(innerV, k)
        }
    }
    return collection
}
var ret = each(["foo":true, "bar":false]) { println("Key \($1), Value:\($0)") }

正在进行的词典实施

func eachDictionary<K,V>(collection: Dictionary<K, V>, fn: (V, K) -> ()) -> Dictionary<K, V> {
    for (_, (k, v)) in enumerate(collection) {
        fn(v, k)
    }
    return collection
}
var retDictionary = eachDictionary(["foo":true, "bar":false]) { println("Key \($1), Value:\($0)") }

正在运行的数组实现

func each<V>(collection: V[], fn: (V, Int) -> ()) -> V[] {
    for (k, v) in enumerate(collection) {
        fn(v, k)
    }
    return collection
}
var retArray = each([true, false]) { println("Key \($1), Value:\($0)") }

编辑2:更新了使用重载的示例。 我具体询问是否有通用的收集协议方法来实现这一点,而不需要为每种收集类型提供一次性服务?

编辑3:我尝试了以下内容(我必须在空数组中添加更多类型,以便它不会抱怨回调的参数不可打印)但是......

  1. 现在无法使用词典(将(K,V)作为值传递)
  2. [(V1,V2)]案例
  3. 失败
  4. 我非常想找到一种方法来使用泛型(K, V)代替(Any, Any)
  5. 代码:

    func each<C: Collection>(collection: C, fn: (Any, Any) -> ()) -> C {
        for (k, v) in enumerate(collection) {
            if let (key, value) = v as? (Any, Any) {
                fn(value, key)
            } else {
                fn(v, k)
            }
        }
        return collection
    }
    var ret = each(["foo":true, "bar":false]) { println("1: Key \($1), Value:\($0)") }
    var arr : String[] = []
    var retOne = each(arr) { println("2: Key \($1), Value:\($0)") }
    var retTwo = each([true, false]) { println("3: Key \($1), Value:\($0)") }
    

2 个答案:

答案 0 :(得分:2)

JavaScript和Swift之间最大的区别之一是你可以定义具有不同签名(重载)的相同名称的(function | method)。只需使用它。

class $ {
    class func map<K:Hashable,V,R>
        (dictionary:[K:V], block:(V,K)->R)->[K:R] {
        var result = [K:R]()
        for (k, v) in dictionary {
            result[k] = block(v, k)
        }
        return result
    }
    class func map<V,R>
        (array:[V], block:(V,Int)->R)->[R] {
        var result = [R]()
        for (k, v) in enumerate(array) {
            result.append(block(v, k))
        }
        return result
    }
    class func each<K:Hashable,V,R>
        (dictionary:[K:V], block:(V,K)->R) {
        for (k, v) in dictionary { block(v, k) }
    }
    class func each<V,R>
        (array:[V], block:(V,Int)->R) {
        for (k, v) in enumerate(array) { block(v, k) }
    }
}

println($.map(["zero":0, "one":1], { n,_ in n+1 }))
println($.map([0,1],               { n,_ in n+1 }))
$.each(["zero":0, "one":1]) { println("\($1) => \($0)") }
$.each([0, 1])              { println("\($1) => \($0)") }

答案 1 :(得分:1)

枚举不是你的问题。字典是。您尝试做的事情不太可行,因为这不是基于Collection的含义。 Dictionary中的键与传递给Array的整数无关。词典的索引是DictionaryIndex,而不是KeyType

首先,让我们考虑如何将其写为通用函数(不能做你想要的,但正是你可以在Collection上做的):

func each<C:Collection>(collection: C, fn:(C.GeneratorType.Element, C.IndexType) -> ()) -> C {
  for index in indices(collection) {
    fn(collection[index], index)
  }
  return collection
}

它遍历集合并将其值和索引传递给接受它们的某个函数。对于数组,此函数将具有签名:

(T, Int) -> ()

对于词典,此函数将具有签名

(ValueType, DictionaryIndex<KeyType, ValueType>) -> ()

您对enumerate的使用只会掩盖这一根本问题。 Collection是一个Sequence,它通过下标传递索引时返回一个值。这就是全部。序列是可以通过生成器生成值的东西。这就是全部。在这两者之间,他们对字典键一无所知。从通用的角度来看,字典只是一系列键/值元组。

现在,你喜欢的真实情况是,Dictionary的索引是它的键。但事实并非如此。讨论Dictionary的密钥没有通用的方法,因为它们不是Collection协议的一部分(而且Array和Dictionary共享没有其他常见的协议可以挂起来)。

那么为什么,你可能会问,你能说dict[key]并获得价值吗?这与Collection无关。这是Dictionary中的一个额外的下标方法(评论我的):

// This is the Collection subscript
subscript (i: DictionaryIndex<KeyType, ValueType>) -> (KeyType, ValueType) { get }

// This is a subscript unrelated to Collection
subscript (key: KeyType) -> ValueType?

由于Collection对Dictionaries的键一无所知,因此几乎肯定不可能解决这个问题。

我怀疑Dictionary的键不是索引的原因与dict[key]返回Optional的事实有关,而array[num](通常是Collection的下标)返回实际值。