获取Swift中泛型类型的名称(字符串)

时间:2014-08-25 06:16:37

标签: generics types swift introspection

我有一个类型为T的泛型类,我希望获得在实例化时传递给类的类型的名称。这是一个例子。

class MyClass<T> {
    func genericName() -> String {
        // Return the name of T.
    }
}

我一直在寻找几个小时,我似乎无法找到任何方法来做到这一点。有人试过这个吗?

非常感谢任何帮助。

由于

6 个答案:

答案 0 :(得分:18)

您可以使用字符串插值返回任何类型的名称:

    <video id="video" class="video-js vjs-default-skin"
    controls width="640" height="264">
        <source src="{{ video.url }}" type='video/mp4' /></source>
        <p class="vjs-no-js">To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="http://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a></p>
    </video> 

你可以在游乐场尝试它并按预期工作:

.filter('trusted', function($sce) {
  return function(url) {
    return $sce.trustAsResourceUrl(url);
  };
})

答案 1 :(得分:12)

Swift 3 +中的

String(describing: T.self)

var genericTypeName: String {
    return String(describing: T.self)
}

在通用类型中,通过将TT.self转换为type(of: T.self)来获取类型String的名称。我发现type(of:)不是必需的,但值得注意,因为在其他情况下它会删除有关Type的其他细节。

以下示例演示了如何在结构和类中获取泛型类型T的名称。它包含获取包含类型名称的代码。

包括类和结构

的示例
struct GenericStruct<T> {
    var value: T

    var genericTypeName: String {
        return String(describing: T.self)
    }

    var genericTypeDescription: String {
        return "Generic Type T: '\(genericTypeName)'"
    }

    var typeDescription: String {
        // type(of:) is necessary here to exclude the struct's properties from the string
        return "Type: '\(type(of: self))'"
    }
}

class GenericClass<T> {
    var value: T

    var genericTypeName: String {
        return String(describing: T.self)
    }

    var genericTypeDescription: String {
        return "Generic Type T: '\(genericTypeName)'"
    }

    var typeDescription: String {
        let typeName = String(describing: self)
        return "Type: '\(typeName)'"
    }

    init(value: T) {
        self.value = value
    }
}

enum TestEnum {
    case value1
    case value2
    case value3
}

let intGenericStruct: GenericStruct<Int> = GenericStruct(value: 1)
print(intGenericStruct.typeDescription)
print(intGenericStruct.genericTypeDescription)

let enumGenericStruct: GenericStruct<TestEnum> = GenericStruct(value: .value2)
print(enumGenericStruct.typeDescription)
print(enumGenericStruct.genericTypeDescription)

let intGenericClass: GenericClass<Int> = GenericClass(value: 1)
print(intGenericClass.typeDescription)
print(intGenericClass.genericTypeDescription)

let enumGenericClass: GenericClass<TestEnum> = GenericClass(value: .value2)
print(enumGenericClass.typeDescription)
print(enumGenericClass.genericTypeDescription)

控制台输出

/*
Type: 'GenericStruct<Int>'
Generic Type T: 'Int'

Type: 'GenericStruct<TestEnum>'
Generic Type T: 'TestEnum'

Type: 'GenericClass<Swift.Int>'
Generic Type T: 'Int'

Type: 'GenericClass<TestEnum>'
Generic Type T: 'TestEnum'
*/

答案 2 :(得分:9)

实现这一目标的纯粹快捷方式是不可能的。

可能的解决方法是:

class MyClass<T: AnyObject> {
    func genericName() -> String {
        let fullName: String = NSStringFromClass(T.self)
        let range = fullName.rangeOfString(".", options: .BackwardsSearch)
        if let range = range {
            return fullName.substringFromIndex(range.endIndex)
        } else {
            return fullName
        }
    }
}

这些限制依赖于它仅适用于类的事实。

如果这是通用类型:

class TestClass {}

NSStringFromClass()返回全名(包括命名空间):

// Prints something like "__lldb_expr_186.TestClass" in playground
NSStringFromClass(TestClass.self)

这就是func搜索.字符的最后一次出现的原因。

测试如下:

var x = MyClass<TestClass>()
x.genericName() // Prints "TestClass"

更新Swift 3.0

func genericName() -> String {
    let fullName: String = NSStringFromClass(T.self)
    let range = fullName.range(of: ".")
    if let range = range {
        return fullName.substring(from: range.upperBound)
    }
    return fullName
}

答案 3 :(得分:1)

如果您的类型参数实现了通用的命名协议,那么这是可能的。

在下面的示例中,协议Named确保泛型类型实现name类属性。

请注意,这适用于类和值类型,因为后者也可以扩展为符合协议,如下面的Int所示。

protocol Named {
    class var name: String { get }
}

class MyClass<T: Named> {
    func genericName() -> String {
        return T.name
    }
}

extension Int: Named {
    static var name: String { return "I am an Int" }
}

class Foo: Named {
    class var name: String { return "I am a Foo" }
}

enum Drink: Named {
    static var name: String { return "I am a Drink" }
}

MyClass<Int>().genericName()  // I am an Int
MyClass<Foo>().genericName()  // I am a Foo
MyClass<Drink>().genericName()  // I am a Drink

答案 4 :(得分:1)

另一种可能对某人有帮助的解决方案:

游乐场

{{1}}

答案 5 :(得分:0)

为我工作:

class MyClass<T> {
    func genericName() -> String {
        return "\(type(of: self))"
    }
}