我可以指定泛型是值类型吗?

时间:2015-02-28 13:57:57

标签: swift generics value-type reference-type

我知道我们可以使用AnyObject来指定我们的泛型是任何引用类型:

class Foo<T: AnyObject> {
    // ...
}

但有没有办法指明我们的泛型应该只是类型,而不允许引用类型?

2 个答案:

答案 0 :(得分:3)

// some code for testing    
class C { } // just a simple class as an example for a reference type
var c = C()
var d: Double = 0.9 // a value type

解决方案1通过extension

protocol ValueType { }
extension Double : ValueType { }
extension Int : ValueType { }
// ... all value types to be added

func printT1 <T: ValueType> (input: T) {
    println("\(input) is value")
}
printT1(d) // Does work
//printT1(c) // Does not work

但正如评论中所提到的,它是有效但不可行,因为用户定义的值类型必须实现此协议。


解决方案2通过方法签名

func printT <T: AnyObject> (input: T) {
    println("\(input) is reference")
}

func printT <T: Any> (input: T) {
    println("\(input) is value")
}

解决方案3通过assert

另一种解决方案可以是assert

func printT <T: Any> (input: T) {
    print("\(input) is " + ((T.self is AnyObject) ? "reference" : "value"))
}

“解决方案”4通过where条款

我认为这是最好的解决方案。不幸的是,不可能有

func printT <T: Any where T: ~AnyObject > (input: T) {
    println("\(input) is value")
}

或类似的。也许在未来的Swift版本中它是可能的。

答案 1 :(得分:-2)

如果您足以使用断言

public final class Synchronized<T> {
    private var _value: T        
        
    public init(_ value: T) {
       assert(!isReferenceType(value))
       _value = value
    }
    ...
}
    
func isReferenceType(_ any: Any) -> Bool {
    return Mirror(reflecting: any).displayStyle == .class
}

一些单元测试证明它可以正常工作:

import XCTest

final class SynchronizedTests: XCTestCase {
    class FakeClass {}
    struct FakeStruct {}
    enum FakeEnum {
        case first
    }

    func testIsReferenceType() {
        XCTAssert(isReferenceType(FakeClass()))

        XCTAssertFalse(isReferenceType(FakeStruct()))
        XCTAssertFalse(isReferenceType(FakeEnum.first))
        XCTAssertFalse(isReferenceType("string"))
        XCTAssertFalse(isReferenceType(123))
        XCTAssertFalse(isReferenceType(123.4))
        XCTAssertFalse(isReferenceType([1, 2, 3]))
        XCTAssertFalse(isReferenceType(Set([1, 2, 3])))
        XCTAssertFalse(isReferenceType(["1": 1, "2": 2, "3": 3]))
    }
}