タイプTのジェネリッククラスがあり、インスタンス化されたときにクラスに渡されたタイプの名前を取得したいと考えています。ここに例があります。
class MyClass<T> {
func genericName() -> String {
// Return the name of T.
}
}
私は何時間も探し回っていましたが、これを行う方法を見つけることができません。誰かこれをまだ試しましたか?
どんな助けでも大歓迎です。
ありがとう
純粋なSwiftそれを達成する方法は不可能です。
可能な回避策は次のとおりです。
_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"
_
PDATE Swift 3.
_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
}
_
文字列補間を使用して、任意の型の名前を返すことができます。
class MyClass<T> {
func genericName() -> String {
return "\(T.self)"
}
}
あなたはそれを遊び場で試すことができ、それは期待通りに機能します:
var someClass = MyClass<String>()
someClass.genericName() // Returns "Swift.String"
String(describing: T.self)
in Swift 3+_var genericTypeName: String {
return String(describing: T.self)
}
_
ジェネリック型内で、_T.self
_またはtype(of: T.self)
をT
に変換して、型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'
*/
_
誰かを助けるかもしれない別の可能な解決策:
遊び場
import Foundation
class ClassType<T> {
static func name () -> String
{
return "\(T.self)".componentsSeparatedByString(".").last!
}
}
class MyClass {
}
func testClassName(){
let className = ClassType<MyClass>.name()
print(className)
}
testClassName()
タイプパラメータが一般的な命名プロトコルを実装している場合は可能です。
以下の例では、プロトコル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