我有一些扩展功能,我想进入成员功能。但是我不确定如何做到这一点,尤其是对于嵌套的通用类型链。
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)
}
如何将接收方具有泛型类型的扩展功能转换为成员函数?有没有一种方法可以将运算符放在类中,或者扩展是实现此目标的唯一方法?我已经尝试过类似的方法,但是它不起作用:
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
}
答案 0 :(得分:1)
首先,我只想说:这是除法运算符功能的明显滥用。仅仅使用/
的除法就忽略了除数?但是,老实说,这也是在代码中使用/
的一种有趣方式;-)尽管如此,我还是不建议这样做。查看您的代码。您现在有很多未使用的除数;-)除了免责声明,让我们解决您的问题。
特定问题的解决方案并不像您想象的那样好。您对扩展功能所做的工作并不那么容易移至成员函数。原因:将扩展功能的使用范围缩小到特定的泛型类型。如果您希望与成员相同,则也需要在此缩小范围。如果查看扩展函数是什么(静态方法调用),则在实现类中也可能需要相同的结构。以下示例有效,但不能缩小层次结构:
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
}
因此,如果您允许usr
在...anything
下,那么/...anything/usr/local可能会起作用。
要回答您的一般性问题“扩展功能能否始终转换为成员功能?”这取决于。当使用泛型时,肯定不会1:1。也许这会导致一个新的类层次结构,并最终删除您的泛型信息;-)但这也可能最终效果不佳。
但是,正如我们写的很多...这是以前的解决方案(第二部分中仍然写有“不编译!”,但现在改编为“必须不编译!” ;-)) >
您可能已经认识到,无法推断出您的类型T
。但是,正如您已经考虑过使用T : usr<localhost_>>
一样,为什么不首先省略泛型类型信息呢?
如果将其删除,您的代码仍然可以按预期运行并且说实话,您甚至都没有使用过任何对泛型有用的东西;-)
如果您在那里,还可以省略扩展功能,因为您将不再需要扩展功能,并且如果您想缩小可以调用的范围(例如,应允许使用localhost_/usr/local/bin
,但不能使用localhost_/usr/local/usr/local/bin
),那么泛型可能就不行了。
这是没有泛型且没有扩展功能的示例:
abstract class File
open class Y private constructor() {
open class localhost_ {
@JvmName("usr") operator fun div(a: usr.Companion) = usr()
@JvmName("bin") operator fun div(a: bin.Companion) = bin()
@JvmName("etc") operator fun div(a: etc.Companion) = etc()
companion object {
operator fun div(a: usr.Companion) = usr()
operator fun div(a: bin.Companion) = bin()
operator fun div(a: etc.Companion) = etc()
}
}
// hierarchies are also built as class hierarchies
open class bin: File() {
operator fun div(a: sh.Companion) = sh()
open class sh: File() { companion object }
companion object }
open class etc: File() {
operator fun div(a: etc.vim.Companion) = etc.vim()
open class vim: File() { companion object }
companion object }
open class usr: File() {
operator fun div(a: usr.bin.Companion) = usr.bin()
operator fun div(a: usr.local.Companion) = usr.local()
open class bin: File() {
operator fun div(a: usr.bin.vim.Companion) = usr.bin.vim()
open class vim: File() { companion object }
companion object }
open class local : File() {
operator fun div(a: local.bin.Companion) = local.bin()
open class bin : File() { companion object }
companion object }
companion object }
companion object { fun uri(path: Any) = println(path) }
}
但是,调用它确实看起来并不好(因为您随后需要导入适当的类型...您仍然可以将叶子放在类层次结构之外,但这实际上是不相同的;-)(现在是{{1 }是一片叶子,但是如果以后有文件夹vim
怎么办?)
vim
但是,由于您没有将除法用作除法,因此最好还是省略它(因为您甚至不会获得漂亮的/有用的代码完成),例如通过使用以下任一方法:
Y.uri(localhost_)
Y.uri(localhost_)
Y.uri(localhost_ / bin)
Y.uri(localhost_ / bin / bin.sh)
Y.uri(localhost_ / etc)
Y.uri(localhost_ / etc / etc.vim)
Y.uri(localhost_ / usr)
Y.uri(localhost_ / usr / usr.bin / usr.bin.vim)
Y.uri(localhost_ / usr / usr.local)
Y.uri(localhost_ / usr / usr.local / usr.local.bin)
,或者使用经过修饰的类型和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>()
}
通过这种方式,您甚至可以获得有用的代码完成。
这是一个示例,我仍然不建议这样做,该示例在后面使用了运算符和修饰函数的组合:
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
}
函数。我没有进一步详细说明;-)
正如您自己指出的那样,您甚至可以使用属性...实际上,您应该考虑很多事情,而不是滥用泛型和除法;-)