Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 泛型的使用_Swift_Generics_Types - Fatal编程技术网

Swift 泛型的使用

Swift 泛型的使用,swift,generics,types,Swift,Generics,Types,我有以下结构: struct A<T> { var val: T } struct B<T> { var setOfA: Set<A<T>> } 结构A{ var val:T } 结构B{ 变量集合:集合 } 如果As集合可以同时具有A和A类型(或任何其他类型)的值,则泛型的使用是否不正确 如果是,使用Any是否正确 如果As的集合被限制为单个类型的As,则泛型是正确的选择吗?如果您计划让结构包含特定类型的val,请使用。如果

我有以下结构:

struct A<T> {
    var val: T
}

struct B<T> {
    var setOfA: Set<A<T>>
}
结构A{ var val:T } 结构B{ 变量集合:集合 } 如果
A
s集合可以同时具有
A
A
类型(或任何其他类型)的值,则泛型的使用是否不正确

如果是,使用
Any
是否正确


如果
A
s的集合被限制为单个类型的
A
s,则泛型是正确的选择吗?

如果您计划让结构包含特定类型的
val
,请使用
。如果类型不重要,并且您的
val
可以是任何类型,只需将结构实现为
struct A{}
A
等于
A

请注意,如果您希望使用不同类型的
setOfA
包含
A
,那么您的示例将无法编译

集合中的元素必须是可散列的

B
中,
T
仅表示一种类型。因此,您不能在
集中存储不同的类型

由于这一要求,
struct A
必须符合
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
A
,则
var setOfA:set
是正确的方法

如果
struct A
有一个非常特定的用例,并且您实际上不需要它是泛型的,那么您应该更改
val
的类型。您的代码应该是可理解和全面的。我将推荐以下解决方案之一:

struct A: Hashable {
    
    var val: Any
    // or
    var val: Numeric

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

首先,如果希望在集合中插入
A
项,则类型必须实现
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
    }
}
不幸的是,这并没有将集合限制为仅为任何
T
保存
A
类型的值

setOfA
的类型不能是
Set
,因为对于一些
T
的人来说,这需要一个类型为
a
的值才能转换为
a
,而Swift不支持这一点(研究方差可能有助于理解原因)

您可能想知道为什么不能设置该类型。不幸的是(在此上下文中!)
Hashable
是一个具有
Self
要求的协议,Swift不支持在此上下文中将其用作泛型类型参数
AnyHashable
是一种非泛型的
struct
,它的类型会擦除它所包装的值(存在类型位)

因此,回到解决将集合约束为仅包含
A
的问题上来。一种解决方案是在
B
中隐藏(
private
)集合,并提供一个通用插入函数,对于任何
T
,该函数只接受
a
值。然后,可以使用只读计算属性公开设置值本身。例如:

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)
    }
}
结构B { //私有属性,因此只有B的函数可以修改集合 私有变量_setOfA:Set=Set() //公共只读属性,因此无法直接更改_setOfA var setOfA:Set{return\u setOfA} //对于任何T,只接受A值的公共插入函数 变异函数插入(u元素:A)->(布尔,A) { 返回_setOfA.insert(元素) } }
下面是使用上述代码的dome示例代码:

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))")
    }
}
设x=A(val:4)//x:A
让y=A(val:hello)//y:A
var z=B()
print(z.insert(x))//作为泛型的insert接受任何
打印(z.插入(y))
print(z.insert(x))//应返回(false,x)作为已添加的元素
打印(“\(z)”)
对于z.setOfA中的成员
{
打印(“成员=\(成员):\(类型:成员)))
如果让intMember=成员为?A
{
打印(“intMember=\(intMember):\(类型(of:intMember)))
}
否则,如果让stringMember=成员为?A
{
打印(“stringMember=\(stringMember):\(类型(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>
(正确,uu lldb_expr_501.A(val:4))
(没错,lldb expr 501.A(val:“你好”))
(假,lldb expr 501.A(val:4))
B(_setOfA:Set([AnyHashable(u lldb_expr_501.A(val:“hello”)),AnyHashable(u lldb_expr_501.A(val:4)))
member=A(val:“hello”):AnyHashable
stringMember=A(val:“你好”):A
member=A(val:4):AnyHashable
intMember=A(val:4):A

HTH

您可能只是能够使它们符合。Int和Float只是示例。它可以是任何类型。可能的副本需要使您的结构和泛型类型符合Hashable
struct A:Hashable{var val:T}
struct B{var setOfA:Set}
@LeoDabus不需要
struct B
符合
Hashable
,也不需要
T
这样做。对于
B
中的泛型类型
T
Set
中的
A
s只能是相同的类型。这里的问题是不再推断该类型。var aSet=Set()让v1=A(val:4)作为let v2=A(val:5.5)作为aSet.insert(v1)aSet.insert(v2)如果我不写-“作为”它给我一个编译时错误-“无法将类型A的值转换为预期的参数类型A”@KunalShah它不会给我带来任何错误。我使用Swift 4.2和Xcode 10 Beta版,但这不会有什么区别。当我尝试使用
ArrayLiteral
初始化
Set
时,我也遇到了一个编译时错误:
let Set:Set=[a(val:0为Int),a(val:1为Float)]
。您评论中的代码在Xcode中没有给我错误。@KunalShah是的,对不起。我现在明白问题所在了。编译广域网
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>