到目前为止,我了解到 typealias 是现有类型的命名别名。通过使用类型别名,我可以做类似的事情:
typealias MyString = String
var str: MyString?
typealias Strings = [String]
var strs: Strings?
这导致将
str
变量声明为字符串,将 strs
声明为字符串数组。
即使对于自定义类型:
class MyClass {}
typealias MyClsType = MyClass
var myClass: MyClsType
不过,好像有点没用;从逻辑上讲,将
var str: MyString?
声明为字符串而不是 var str: String?
的目的是什么?更重要的是,var str: String
更具表现力。
实际上,毫无疑问,为字符串创建类型别名:
typealias MyString = String
不会那么有用,(我还假设为具有特定键/值类型的字典声明类型别名:typealias CustomDict = Dictionary<String, Int>
可能会对你没那么有用。
但是,当涉及到复合类型时,您肯定会注意到类型别名的好处。
示例:
考虑您正在实现管理器,它在其函数中重复使用带有许多参数的闭包:
class MyManager {
//...
func foo(success: (_ data: Data, _ message: String, _ status: Int, _ isEnabled: Bool) -> (), failure: (_ error: Error, _ message: String, _ workaround: AnyObject) -> ()) {
if isSuccess {
success(..., ..., ..., ...)
} else {
failure(..., ..., ...)
}
}
func bar(success: (_ data: Data, _ message: String, _ status: Int, _ isEnabled: Bool) -> (), failure: (_ error: Error, _ message: String, _ workaround: AnyObject) -> ()) {
if isSuccess {
success(..., ..., ..., ...)
} else {
failure(..., ..., ...)
}
}
// ...
}
如您所见,方法签名看起来真的很乏味!这两种方法都带有
success
和 failure
参数,它们都是带有参数的闭包;此外,为了实现类似的功能,保持复制粘贴参数并不符合逻辑。
针对这种情况实施
typealias
是非常合适的:
class MyManager {
//...
typealias Success = (_ data: Data, _ message: String, _ status: Int, _ isEnabled: Bool) -> ()
typealias Failure = (_ error: Error, _ message: String, _ workaround: AnyObject) -> ()
func foo(success: Success, failure: Failure) {
if isSuccess {
success(..., ..., ..., ...)
} else {
failure(..., ..., ...)
}
}
func bar(success: Success, failure: Failure) {
if isSuccess {
success(..., ..., ..., ...)
} else {
failure(..., ..., ...)
}
}
// ...
}
因此它会更具表现力和可读性。
此外,您可能想查看我发布的关于它的媒体故事。
对我来说使用类型别名的常见方法是使用闭包:
typealias VoidClosure = () -> Void
func updateFrom(completion: @escaping VoidClosure) { }
在 Swift 中,对我来说很奇怪,他们将它用于简单类型,例如:
typealias CLLocationSpeed = Double
https://developer.apple.com/documentation/corelocation/cllocationspeed
在 Kotlin 中更有意义:
类型别名为现有类型提供替代名称。如果类型名称太长,您可以引入一个不同的较短名称并使用新名称。
缩短长泛型类型很有用。例如,缩小集合类型通常很诱人:
typealias NodeSet = Set<Network.Node>
typealias FileTable<K> = MutableMap<K, MutableList<File>>
您可以为函数类型提供不同的别名:
typealias MyHandler = (Int, String, Any) -> Unit
typealias Predicate<T> = (T) -> Boolean
您可以为内部类和嵌套类使用新名称:
class A {
inner class Inner
}
class B {
inner class Inner
}
typealias AInner = A.Inner
typealias BInner = B.Inner
类型别名不会引入新类型。它们相当于相应的底层类型。当您在代码中添加
typealias Predicate<T
并使用 Predicate<Int>
时,Kotlin 编译器始终将其扩展为 (Int) -> Boolean
。因此,只要需要通用函数类型,您就可以传递您类型的变量,反之亦然:
typealias Predicate<T> = (T) -> Boolean
fun foo(p: Predicate<Int>) = p(42)
fun main() {
val f: (Int) -> Boolean = { it > 0 }
println(foo(f)) // prints "true"
val p: Predicate<Int> = { it > 0 }
println(listOf(1, -2).filter(p)) // prints "[1]"
}