代码之家  ›  专栏  ›  技术社区  ›  sirksel

拳击弦场或扩展Kotlin中所有弦的替代方案?

  •  3
  • sirksel  · 技术社区  · 7 年前

    鉴于不能在Kotlin中对内置类型进行子类化,我正在寻找一种方法,将特殊方法功能添加到 字符串字段的特定类型 在记录中,不将这些扩展函数应用于 所有字符串 (即使在该记录类型内)。例如,我在一个记录中有一些可变的字符串字段,我想为其定义特殊用途的行为。

    class Customer {
      // ...
      var zipcode: String
      var email: String
      // ...
    }
    
    • 对于 zipcode ,假设我想打电话 thisCustomer.zipcode.plusFour 获取邮政编码的+4(99999- 9999 )通过正则表达式。
    • 对于 email ,假设我想打电话 thisCustomer.email.domain 要有正则表达式,请获取@ 公司通用域名格式 指定电子邮件的一部分。

    我的目标是:

    1. 避免装箱的运行时开销 zipcode码 变成一个 class Zipcode 只有一个 考虑到客户记录集的大小可能达到数百万,内部只有一个var。
    2. 避免必须赋值的语法 thisCustomer.zipcode.value = "99999-9999" thisCustomer.zipcode = Zipcode("99999-9999")
    3. 避免添加常规 String.plusFour String.domain 班因为从技术上讲,zipcodes和电子邮件可以互相调用

    我一直在考虑这一点,并考虑了以下选项,但删除了每一个:

    • 子类化字符串: 不可能,因为字符串(和所有内置) 已关闭
    • 将接口Zip应用于var声明( var zipcode: String, Zip ): 我找不到这样的语法
    • 在getter本身中添加内部函数: 对此似乎不存在语法
    • 在函数中使用对象或函数: 想不出办法 虽然我可能没有足够的想象力

    我是否错过了一个显而易见的解决方案?即使不明显,有了Kotlin所有的句法魔力,有没有办法实现这一点?也许有一种方法可以在不使用任何这些方法的情况下实现上述部分/所有目标?

    2 回复  |  直到 7 年前
        1
  •  3
  •   Alexey Romanov    7 年前

    您可以使用 type aliases 为了明确意图:

    typealias ZipCode = String
    val ZipCode.plusFour get() = ...
    
    typealias Email = String
    val Email.domain get() = ...
    
    class Customer {
      // ...
      var zipcode: ZipCode
      var email: Email
      // ...
    }
    

    不幸的是 只有 zipcode.domain . 但现在我不认为有任何方法可以同时满足目标1和3。

    Kotlin开发人员决定不支持与赋值不兼容的类型别名,因为它可以满足您的所有需求,而支持等待值类在JVM上可用,如中所述 https://github.com/Kotlin/KEEP/issues/4 .

        2
  •  1
  •   Jacky Choi    7 年前

    您可以使用委托创建装饰器类:

    class YourString(val value: String) : Comparable<String> by value, CharSequence by value {
    
        val plusFour: String
            get() = ""  //your logic here
    
        val domain: String
            get() = ""  //your logic here
    
        override fun toString() = value
    }
    

    用法:

    fun String.toYourString() = YourString(this)
    
    class Customer(var zipCode: YourString, var email: YourString)
    
    val customer = Customer("+4 99999-9999".toYourString(), "xxx@company.com".toYourString())
    println(customer.zipCode.plusFour)
    println(customer.email.domain)