Kotlin 扩展函数是否可以始终转换为成员?

Kotlin 扩展函数是否可以始终转换为成员?,kotlin,Kotlin,我有一些扩展函数,我想转到成员函数。但我不知道如何做到这一点,特别是对于嵌套泛型类型链 import Y.* abstract class File<T> open class Y private constructor() { open class localhost_ { @JvmName("usr") operator fun div(a: usr.Companion) = usr<localhost_>() @JvmName("bin")

我有一些扩展函数,我想转到成员函数。但我不知道如何做到这一点,特别是对于嵌套泛型类型链

import Y.*

abstract class File<T>

open class Y private constructor() {
  open class localhost_ {
    @JvmName("usr") operator fun div(a: usr.Companion) = usr<localhost_>()
    @JvmName("bin") operator fun div(a: bin.Companion) = bin<localhost_>()
    @JvmName("etc") operator fun div(a: etc.Companion) = etc<localhost_>()

    companion object: localhost_()
  }

  open class bin<T>: File<T>() { companion object }
  open class sh<T>: File<T>() { companion object }
  open class etc<T>: File<T>() { companion object }
  open class vim<T>: File<T>() { companion object }
  open class usr<T>: File<T>() { companion object }
  open class local<T>: File<T>() { companion object }

  companion object { fun uri(path: Any) = println(path) }
}

operator fun bin<localhost_>.div(a: sh.Companion) = sh<bin<localhost_>>()
operator fun bin<usr<localhost_>>.div(a: vim.Companion) = vim<bin<usr<localhost_>>>()
operator fun etc<localhost_>.div(a: vim.Companion) = vim<etc<localhost_>>()
operator fun usr<localhost_>.div(a: bin.Companion) = bin<usr<localhost_>>()
operator fun usr<localhost_>.div(a: local.Companion) = local<usr<localhost_>>()
operator fun local<usr<localhost_>>.div(a: bin.Companion) = bin<local<usr<localhost_>>>()

/**
 * localhost_/
 * ├── bin/
 * │   └── sh
 * ├── etc/
 * │   └── vim
 * └── usr/
 *     ├── bin/
 *     │   └── vim
 *     └── local/
 *         └── bin/
 */

fun main(a: Array<String>) {
  //Compiles!
  Y.uri(localhost_)
  Y.uri(localhost_/bin)
  Y.uri(localhost_/bin/sh)
  Y.uri(localhost_/etc)
  Y.uri(localhost_/etc/vim)
  Y.uri(localhost_/usr)
  Y.uri(localhost_/usr/bin/vim)
  Y.uri(localhost_/usr/local)
  Y.uri(localhost_/usr/local/bin)


  //Does not compile!
  Y.uri(localhost_/local)
  Y.uri(localhost_/bin/vim)
  Y.uri(localhost_/sh)
  Y.uri(localhost_/bin/local)
  Y.uri(localhost_/etc/local)
  Y.uri(localhost_/etc/sh)
  Y.uri(localhost_/usr/local/usr)
}
导入Y*
抽象类文件
开放类Y私有构造函数(){
开放类localhost\u{
@JvmName(“usr”)操作符fun div(a:usr.Companion)=usr()
@JvmName(“bin”)操作员fun div(a:bin.Companion)=bin()
@JvmName(“etc”)操作员fun div(a:etc同伴)=etc()
伴生对象:localhost(()
}
打开类bin:File(){companion object}
打开类sh:File(){companion object}
打开类etc:File(){companion object}
打开类vim:File(){companion object}
打开类usr:File(){companion object}
打开本地类:File(){companion object}
伴随对象{fun uri(路径:Any)=println(路径)}
}
操作员趣味箱分区(a:sh.Companion)=sh()
操作员娱乐箱分区(a:vim.Companion)=vim()
操作员娱乐等部门(a:vim.Companion)=vim()
操作员乐趣usr.div(a:bin.Companion)=bin()
操作员fun usr.div(a:local.Companion)=local()
操作符fun local.div(a:bin.Companion)=bin()
/**
*本地主机_/
* ├── 垃圾箱/
* │   └── 嘘
* ├── 等/
* │   └── 维姆
* └── usr/
*     ├── 垃圾箱/
*     │   └── 维姆
*     └── 本地的/
*         └── 垃圾箱/
*/
趣味主打(a:阵列){
//编译!
Y.uri(本地主机)
Y.uri(localhost\uu/bin)
Y.uri(localhost\uu/bin/sh)
Y.uri(本地主机\等)
Y.uri(localhost\u/etc/vim)
Y.uri(localhost\uu/usr)
Y.uri(localhost\uu/usr/bin/vim)
Y.uri(localhost\uu/usr/local)
Y.uri(localhost\uu/usr/local/bin)
//不编译!
Y.uri(本地主机\本地)
Y.uri(localhost\uu/bin/vim)
Y.uri(localhost\ush/sh)
Y.uri(localhost\u/bin/local)
Y.uri(localhost\u/etc/local)
Y.uri(localhost\uu/etc/sh)
Y.uri(localhost\uu/usr/local/usr)
}
如何将接收器具有泛型类型的扩展函数转换为成员函数?有没有办法将运算符函数放入类中,或者扩展是实现这一点的唯一方法?我尝试过类似的方法,但不起作用:

open class usr<T>: File<T>() {
    operator fun <T: usr<localhost_>> div(a: local.Companion) = local<T>()
    operator fun <T: usr<localhost_>> div(a: bin.Companion) = bin<T>()

    companion object
}
开放类usr:File(){
操作员乐趣分区(a:local.Companion)=本地()
操作员娱乐部(a:bin.Companion)=bin()
伴星
}

首先,让我说一下:这是对除法运算符函数的一种相当明显的误用。仅仅为了使用
/
而忽略除数的除法?然而,老实说,在代码中使用
/
也是一种有趣的方式;-)不过,我不能推荐它。看看你的代码。您现在有很多未使用的除数;-)撇开免责声明不谈,让我们来解决您的问题

你具体问题的解决方案并不像你想象的那么好。您对扩展函数所做的操作并不容易移动到成员函数。原因:您将扩展函数的使用范围缩小到特定的泛型类型。如果你想成为同一个会员,你也需要缩小范围。如果查看扩展函数是什么(静态方法调用),那么在实现类中可能还需要相同的结构。例如,以下示例可行,但并未缩小层次结构:

open class usr<T>: File<T>() {
  operator fun div(a: local.Companion) = local<usr<T>>()
  operator fun div(a: bin.Companion) = bin<usr<T>>()
  companion object
}
但是,调用它确实不好看(因为您需要导入适当的类型…您仍然可以将leaf放在类层次结构之外,但这实际上并不相同;-)(现在
vim
是一个leaf,但是如果您有一个文件夹
vim
以后呢?)

但是,同样,由于您没有使用除法作为除法,您可能还是最好省略它(因为您甚至没有获得漂亮/有用的代码完成),例如,通过使用:

Y.uri("localhost_/usr/local/bin")
或者使用具体化类型和连接路径的
StringBuilder

abstract class File {
  val uri = StringBuilder()

  inline fun <reified T> append() : T {
    val clazz = T::class
    uri.append(clazz.simpleName).append("/")
    return clazz.java.newInstance()
  }
}
open class usr: File() {
  fun local() = append<local>()
  fun bin() = append<bin>()
}
通过这种方式,您甚至可以完成有用的代码

下面是一个示例,我仍然不推荐它,它使用操作符和后面的具体化函数的混合:

open class usr: File() {
  operator fun div(a : local.Companion) = append<local>()
  operator fun div(a : bin.Companion) = append<bin>()
  companion object
}
开放类usr:File(){
操作符fun div(a:local.Companion)=append()
运算符fun div(a:bin.Companion)=追加()
伴星
}
请注意,您也可以将重新填充的类型与运算符混合使用,但您需要一个
内联
函数。我没有进一步详细说明;-)
正如你自己指出的,你甚至可以使用属性。。。真的有很多事情你应该考虑,而不是滥用泛型和划分;p> 感谢您详细周到的回复。我对你的解决方案很感兴趣,但读了几遍之后,我看不出它是如何解决问题的。也许我不够聪明。你写道,“为什么不先省略泛型类型信息?如果你在任何地方删除它,你的代码仍然会像你期望的那样工作。”。这句话完全不真实(试试看)。主函数必须按描述的那样工作。我愿意使用函数调用,但同样,主函数必须按描述的那样工作。下面是使用您的语法的规范。编译:
localhost().bin()
localhost().bin().sh()
localhost().usr().bin()
。不编译:
localhost().usr().bin().sh()
。作为参考,您可以在这里找到我的解决方案:我非常确定我测试了您的所有主要条目。我稍后会看一看。也许我错过了一份;-)验证解决方案时,所有“Compiles!”语句都要编译,而“not compile!”语句都不编译,这一点很重要。
abstract class File {
  val uri = StringBuilder()

  inline fun <reified T> append() : T {
    val clazz = T::class
    uri.append(clazz.simpleName).append("/")
    return clazz.java.newInstance()
  }
}
open class usr: File() {
  fun local() = append<local>()
  fun bin() = append<bin>()
}
Y.uri(localhost().usr().local().bin())
// or simply localhost().usr().local().bin().uri
open class usr: File() {
  operator fun div(a : local.Companion) = append<local>()
  operator fun div(a : bin.Companion) = append<bin>()
  companion object
}