Can I specify that a generic is a value type?

后端 未结 2 1442
执念已碎
执念已碎 2021-02-07 06:20

I know that we can essentially specify that our generics be any reference type by using AnyObject:

class Foo {
    // ...
}


        
相关标签:
2条回答
  • 2021-02-07 07:11
    // 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
    

    Solution 1 via 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
    

    But as mentioned in the comments, it is working but not feasible, because user defined value types have to implement this protocol.


    Solution 2 via method signature

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

    Solution 3 via assert

    Another solution could be via assert

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

    "Solution" 4 via where clauses

    This would be the best solution, I think. Unfortunately, it is not possible to have

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

    or similar. Maybe it will be possible in future releases of Swift.

    0 讨论(0)
  • 2021-02-07 07:18

    A possible way if it is enough for you to use Assertion:

    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
    }
    

    Some Unit Tests to prove it works as expected:

    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]))
        }
    }
    
    0 讨论(0)
提交回复
热议问题