java - 使用注解启用 Kotlin typealias 类型检查
问题描述
Kotlin 具有类型别名,在您想要一个好的命名时非常方便。但是,在某些情况下,您希望有一个比别名多一点的类型别名,您希望它强制执行实际的编译时检查,而无需创建新类。
这就是我想要实现的目标:
typealias MyNum = Int
fun isMagical(num: MyNum) = num == 42
fun main() {
// Should fail/warn
isMagical(42)
// Should pass
isMagical(42 as MyNum)
// Should fail/warn
val x = 3
isMagical(x)
// Should pass
val y: MyNum = 3
isMagical(y)
}
我知道我可以使用内联类来实现这一点,但我需要检查其中的许多类型,并且不想为每个类型创建一个类。
可以通过注释来实现吗?喜欢:
@Target(AnnotationTarget.TYPEALIAS)
annotation class StrongType
@StrongType
typealias MyNum = Int
然后让注释处理器进行检查?
我想做一些类似于 Android 的事情@IntDef
:
// Android way (performant but needs to manually annotates methods and list the options in the annotation)
@Retention(SOURCE)
@IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
public @interface NavigationMode {}
public static final int NAVIGATION_MODE_STANDARD = 0;
public static final int NAVIGATION_MODE_LIST = 1;
public static final int NAVIGATION_MODE_TABS = 2;
// Enum way (not performant)
enum class NavMode constructor(val value: Int){
STANDARD(0),
LIST(1),
TABS(2)
}
// Inline class (performant but generating a lot of code)
inline class NavMode(val value: Int) {
companion object {
val STANDARD = NavMode(0)
val LIST = NavMode(1)
val TABS = NavMode(2)
}
}
// This is what I would like: performant, type check in methods without annotating them, clean code
@StrongType
typealias NavMode = Int
const val STANDARD: NavMode = 0
const val LIST: NavMode = 1
const val TABS: NavMode = 2
请注意,这不是我真正的用例,我有很多这样的枚举要创建,同时保持高性能(就像在 android API 中一样)。您认为实现我想要的最可行的方法是什么?谢谢
解决方案
typealias MyNum = Int
表示这MyNum
是 的另一个名称Int
,差不多就是这样。您的“应该警告”检查不起作用,因为 a MyNum
is anInt
和 an Int
is a MyNum
-就类型系统而言,两者之间没有区别。
如果您希望类型系统将它们视为单独的事物,那么您实际上需要一个单独的类型,如果您只想要一个“特殊的 Int”,您会遇到问题,因为Int
它是一个最终类,不幸的是您不能将其子类化. 因此,您将无法仅将其MyInt
视为Int
.
您使用 IntDefs、枚举等的示例有些不同 - 您肯定需要一种新类型,具有一组有限的可能的预定义值。有些语言会允许你这样做,但仍然将其视为Int
- Kotlin 不会。
IntDefs 可能最接近您想要的,您必须在其中注释所有内容,因为这是检查它的方式 - 它在类型系统之外。它很笨拙,但那是因为它是固定的。
密封类可以为您提供所需的“干净”定义:
// or an interface
abstract class MyInt() {
abstract val value: Int
}
// put them inside the sealed class (in {}) if you want them named NavMode.LIST etc
sealed class NavMode(override val value: Int) : MyInt()
object STANDARD : NavMode(0)
object LIST : NavMode(1)
object TABS : NavMode(2)
但这基本上是一个没有枚举的枚举(您可以利用它来确保每个值都是唯一的 - 这里没有检查,您可以为每个值传递 0)
你说你有“效率限制”,但是你呢?就像,在内存中拥有每个枚举的一个实例实际上是一个问题,或者持有对对象而不是原语的引用?IntDefs 是(是吗?这些天你没有听到太多关于它的消息......)推荐的避免这些对象分配和引用的方法,但它是与更复杂的代码的权衡。
枚举很简单,有时这更重要。我建议先进行一些分析,看看使用它们实际上会产生多大的影响,然后再抛出可能是最好的解决方案。只是值得思考!
推荐阅读
- java - 具有相同上下文根的多个 Web 服务
- pandas - 在 groupby 和滚动列之后向 pandas 数据框添加新列
- ios - 获取错误线程 1: EXC_BAD_ACCESS (code=1, address=0x20)
- android - BottomSheetBehavior 填充
- c# - dotnet watch run 命令中的绝对路径不起作用
- terminal - 使用 python 以编程方式更改 linux 终端中的字体大小
- three.js - 三.js setHSL() 设置意想不到的颜色
- code-first - 相关实体查询
- c - 在 windows 上添加 openssl c 语言库
- mongodb - MongoDB - 同时找到 3 个平均值