Могу ли я указать, что универсальный тип является значением?
Я знаю, что мы можем по существу указать, что наши дженерики будут любого ссылочного типа с AnyObject
:
class Foo<T: AnyObject> {
// ...
}
Но есть ли способ указать, что наши дженерики должны быть только типами значений, а не разрешать ссылочные типы?
1 ответ
// 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.
Возможный способ, если вам достаточно использовать 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
}
Некоторые модульные тесты, чтобы доказать, что это работает должным образом:
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]))
}
}