代码之家  ›  专栏  ›  技术社区  ›  Kunal Shah

仿制药的使用

  •  1
  • Kunal Shah  · 技术社区  · 6 年前

    我有以下结构:

    struct A<T> {
        var val: T
    }
    
    struct B<T> {
        var setOfA: Set<A<T>>
    }
    

    如果 A s可以同时具有两个值 A<Int> A<Float> 类型(或任何其他类型)?

    如果是,正在使用 Any 正确的方法?

    如果一组 A S被限制在 A<> 是单一类型的?

    2 回复  |  直到 6 年前
        1
  •  2
  •   CRD    6 年前

    Swift是一个移动目标,所有代码都使用Xcode 9.2和Swift 4.0进行测试。

    A<T> Hashable 协议。您可以根据需要实现这个协议,但为了说明目的,一个简单的方法是需要类型参数 T 并通过间接地 val

    struct A<T> : Hashable where T : Hashable
    {
        var val : T
    
        var hashValue: Int { return val.hashValue }
    
        static func ==(lhs: A<T>, rhs: A<T>) -> Bool
        {
            return lhs.val == rhs.val
        }
    }
    

    A<T> 可哈希

    限制您的 Set A<T> T ,在这个上下文中,它基本上允许将不同类型的值包装在另一个非泛型包装器中。斯威夫特有一些预先定义的存在类型,特别是 AnyHashable B var

    struct B
    {
        var setOfA : Set<AnyHashable> = Set()
    
        ...
    }
    

    不幸的是,这不会将该集限制为仅保留类型的值 对于任何

    的类型 setOfA Set<A<AnyHashable>> 因为这需要类型的值 T A<AnyHashable> 方差

    你可能想知道为什么这个类型不能是 Set<Hashable> 是一个 Self Requirement和Swift不支持在此上下文中将其用作泛型类型参数。 任何哈希表 是一个 非通用 struct 哪一个 类型擦除 (以下简称 存在类型 bit)它所包装的值。

    所以回到解决将集合约束为只包含 A 一个解决办法是隐藏( private )里面的布景 B 并提供一个只接受 A<T> 任何值 T .然后,可以使用只读计算属性将该设置值本身公开。例如:

    struct B
    {
        // private property so only B's functions can modify the set
        private var _setOfA : Set<AnyHashable> = Set()
    
        // public read-only property so _setOfA cannot be changed directly
        var setOfA : Set<AnyHashable> { return _setOfA } 
    
        // public insert function which only accepts A<T> values, for any T
        mutating func insert<T>(_ element : A<T>) -> (Bool, A<T>)
        {
            return _setOfA.insert(element)
        }
    }
    

    下面是使用上面的圆顶示例代码:

    let x = A(val: 4)        // x : A<Int>
    let y  = A(val: "hello") // y : A<String>
    var z = B()
    print(z.insert(x)) // insert being generic accepts any A<T>
    print(z.insert(y))
    print(z.insert(x)) // should return (false, x) as element already added
    print("\(z)")
    for member in z.setOfA
    {
        print("member = \(member) : \(type(of:member))")
        if let intMember = member as? A<Int>
        {
            print("   intMember = \(intMember) : \(type(of:intMember))")
        }
        else if let stringMember = member as? A<String>
        {
            print("   stringMember = \(stringMember) : \(type(of:stringMember))")
        }
    }
    

    此输出:

    (true, __lldb_expr_501.A<Swift.Int>(val: 4))
    (true, __lldb_expr_501.A<Swift.String>(val: "hello"))
    (false, __lldb_expr_501.A<Swift.Int>(val: 4))
    B(_setOfA: Set([AnyHashable(__lldb_expr_501.A<Swift.String>(val: "hello")), AnyHashable(__lldb_expr_501.A<Swift.Int>(val: 4))]))
    member = A<String>(val: "hello") : AnyHashable
       stringMember = A<String>(val: "hello") : A<String>
    member = A<Int>(val: 4) : AnyHashable
       intMember = A<Int>(val: 4) : A<Int>
    

    高温高压

        2
  •  1
  •   Andreas moved to Codidact    6 年前

    如果您计划让结构包含 val 特定类型的,使用 <T: DesiredProtocol> .如果类型无关紧要, 瓦尔 可以是任何类型,只需将结构实现为 struct A<T> {} . A<T> 等于 A<T: Any> .

    请注意,如果您希望 setOfA 包含 A 不同类型。

    A中的元素 Set 必须是可哈希的。

    B<T> ,请 T 仅表示一种类型。因此,不能将不同类型存储在 Set<A<T>> .

    因为这个要求, struct A<T> 必须符合 Hashable 协议,以及 B 必须更改。

    struct A<T>: Hashable {
        var val: T
    
        // Implementation of Hashable
    }
    
    /// This struct should not be generic. It would constrain its setOfA to only contain the same type. 
    /// By removing the generics, and use Any instead, you let each element have its own type.
    struct B {
        var setOfA: Set<A<Any>>
    }
    
    var set: Set<A<Any>> = Set()
    set.insert(A(val: 0 as Int))
    set.insert(A(val: 1 as Float))
    
    let b = B(setOfA: set)
    

    编辑:

    因为您正在寻找一种插入泛型的方法 A<T> 进入之内 A<Any> 不将其类型指定为 A<任何> 关于创作,我想出了两种不同的方法:

    let v1 = A(val: 5)
    var v2 = A(val: 3)
    
    aSet.insert(A(val: v2.val))
    aSet.insert(withUnsafePointer(to: &v3, { return UnsafeRawPointer($0) }).assumingMemoryBound(to: A<Any>.self).pointee)
    

    编辑

    如果是你写的,那 B 塞托法 只会有 A<> 对于单一类型,它是上下文的选择,不管您是否应该使用泛型。问题是如果 struct B 需要是通用的。 struct A 可以是许多不同任务的值类型,而 结构B 不需要。如果 B 更具体地说,你可以写:

    struct B {
        var setOfA: Set<A<Int>>
    }
    

    如前所述,如果您打算将同一个集合包含 A<Int> A<Float> ,然后 var setOfA: Set<A<Any>> 是正确的方法。

    如果 结构A 有一个非常具体的用例,并且您实际上不需要它是通用的,您应该更改 瓦尔 .您的代码应该是可理解和全面的。我将推荐以下解决方案之一:

    struct A: Hashable {
    
        var val: Any
        // or
        var val: Numeric
    
        // Implementation of Hashable
    }