- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
在 Kotlin 中,我看到我可以通过函数 plus()
覆盖 +
以及通过函数 覆盖
...但对于某些东西,比如集合,不存在首选的(集合论)符号/运算符。例如 *
一些运算符>times()A∩B
表示交集,A∪B
表示并集。
我似乎无法定义自己的运算符,没有明确的语法来说明运算符使用什么符号。例如,如果我想为 $$
创建一个函数作为运算符:
operator fun String.$$(other: String) = "$this !!whatever!! $other"
// or even
operator fun String.whatever(other: String) = "$this !!whatever!! $other" // how do I say this is the $$ symbol?!?
我得到了同样的错误:
Error:(y, x) Kotlin: 'operator' modifier is inapplicable on this function: illegal function name
可以创建或覆盖哪些运算符的规则是什么?
注意: 作者有意编写并回答了这个问题 (Self-Answered Questions ),因此常见的 Kotlin 主题的惯用答案出现在 SO 中。
最佳答案
Kotlin 只允许一组非常特殊的 operators to be overridden并且您不能更改可用运算符的列表。
在覆盖运算符时应小心,以保持原始运算符的精神或数学符号的其他常见用法。但有时典型的符号不可用。例如设置联合 ∪
可以很容易地视为 +
因为从概念上讲它是有意义的,这是一个内置运算符 Set<T>.plus()
Kotlin 已经提供了,或者您可以发挥创意并使用 infix function对于这种情况:
// already provided by Kotlin:
// operator fun <T> Set<T>.plus(elements: Iterable<T>): Set<T>
// and now add my new one, lower case 'u' is pretty similar to math symbol ∪
infix fun <T> Set<T>.u(elements: Set<T>): Set<T> = this.plus(elements)
// and therefore use any of...
val union1 = setOf(1,2,5) u setOf(3,6)
val union2 = setOf(1,2,5) + setOf(3,6)
val union3 = setOf(1,2,5) plus setOf(3,6)
或者更清楚的是:
infix fun <T> Set<T>.union(elements: Set<T>): Set<T> = this.plus(elements)
// and therefore
val union4 = setOf(1,2,5) union setOf(3,6)
继续您的集合运算符列表,交集是符号 ∩
所以假设每个程序员都有一个字母'n'看起来的字体∩
我们可以侥幸逃脱:
infix fun <T> Set<T>.n(elements: Set<T>): Set<T> = this.intersect(elements)
// and therefore...
val intersect = setOf(1,3,5) n setOf(3,5)
或通过 *
的运算符重载如:
operator fun <T> Set<T>.times(elements: Set<T>): Set<T> = this.intersect(elements)
// and therefore...
val intersect = setOf(1,3,5) * setOf(3,5)
虽然您已经可以使用现有的标准库中缀函数 intersect()
如:
val intersect = setOf(1,3,5) intersect setOf(3,5)
如果您要发明新事物,则需要选择最接近的运算符或函数名称。例如否定一组枚举,可能使用 -
运算符 ( unaryMinus()
) 或 !
运算符(not()
):
enum class Things {
ONE, TWO, THREE, FOUR, FIVE
}
operator fun Set<Things>.unaryMinus() = Things.values().toSet().minus(this)
operator fun Set<Things>.not() = Things.values().toSet().minus(this)
// and therefore use any of...
val current = setOf(Things.THREE, Things.FIVE)
println(-current) // [ONE, TWO, FOUR]
println(-(-current)) // [THREE, FIVE]
println(!current) // [ONE, TWO, FOUR]
println(!!current) // [THREE, FIVE]
println(current.not()) // [ONE, TWO, FOUR]
println(current.not().not()) // [THREE, FIVE]
请慎重考虑,因为运算符重载可能非常有用,否则会导致困惑和困惑。您必须在保持代码可读性的同时决定什么是最好的。有时,如果运算符符合该符号的规范,或者与原始符号相似的中缀替换,或者使用描述性词以避免混淆,则该运算符是最佳的。
始终检查 Kotlin Stdlib API Reference因为可能已经定义了许多您想要的运算符,或者具有等效的扩展函数。
另一件事......
关于你的$$
运算符,从技术上讲,您可以这样做:
infix fun String.`$$`(other: String) = "$this !!whatever!! $other"
但是因为需要对函数名进行转义,调用起来会很丑:
val text = "you should do" `$$` "you want"
这并不是真正的运算符重载,只有当它是 can me made infix
的函数时才有效。 .
关于operator-overloading - 在 Kotlin 中,我可以覆盖一些现有的运算符,但是创建新的运算符呢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39410946/
“过载”/“过载”在编程方面是什么意思? 最佳答案 这意味着您提供了一个具有相同名称但具有不同签名的函数(方法或运算符)。 例如: void doSomething(); int doSomethin
Kotlin 是允许我们轻松定义各种预定义运算符行为的语言之一,该操作名为运算符重载 - https://kotlinlang.org/docs/reference/operator-overload
所以我正在尝试实现 xorshift PRNG 作为来自 random 的参数化 STL 样式类,例如std::mersenne_twister_engine , 所以我可以将它与来自 random
请给我一个具体的答案,为什么函数覆盖会隐藏基类中重载的函数。 class Base{ public: fun(int,int); fun(B); }; class Derived:public
假设我在 Alloy 4.2 中有以下签名声明: sig Target {} abstract sig A { parent: lone A, r: some Target } sig
我正在对API进行建模,其中方法重载将是一个很好的选择。我的幼稚尝试失败了: // fn attempt_1(_x: i32) {} // fn attempt_1(_x: f32) {} // Er
在方法重载中,重载方法是否可以有不同的返回类型? 例如, void foo(int x) ; int foo(int x,int y); double foo(String str); 在一般的面向对
这个问题已经有答案了: Why is implicit conversion from int to Long not possible? (3 个回答) 已关闭 5 年前。 使用包装类重载方法 vo
我正在为一个 API 建模,其中方法重载非常适合。我天真的尝试失败了: // fn attempt_1(_x: i32) {} // fn attempt_1(_x: f32) {} // Error
我正在为一个 API 建模,其中方法重载非常适合。我天真的尝试失败了: // fn attempt_1(_x: i32) {} // fn attempt_1(_x: f32) {} // Error
1、方法的重载 方法名一样,但参数不一样,这就是重载(overload)。 所谓的参数不一样,主要有两点:第一是参数的个数不一样,第二是参数的类型不一样。只要这两方面有其中的一
我正在设计我自己的编程语言(称为 Lima,如果你在 www.btetrud.com 上关心它),我正在努力思考如何实现运算符重载。我决定在特定对象上绑定(bind)运算符(它是一种基于原型(prot
我正在尝试将运算符用于 Wicket,这非常冗长。 我最想要的功能是使用一元“+”到add()一个组件。 但它需要在每个 MarkupContainer 的上下文中工作。后人。 使用应该是这样的: c
运算符重载如何与函数重载相关联。我的意思是我不太明白如何使用自身已重载的函数来重载运算符。 最佳答案 Operator 只是给中缀函数(写在参数之间的函数)的时髦名称。所以,1 + 2 只是一个 +(
是否有可能过载 __cinit__或 __add__ ? 像这样的东西: cdef class Vector(Base): cdef double x, y, z def __cini
我开始使用 smalltalk,我正在尝试添加一个新的赋值运算符 :> . pharo 中使用的当前运算符不是选择器,所以我开始查看下划线 _ 的类 Scanner可以为分配启用。我试图以类似的方式做
假设我有以下类(class): class A { has $.val; method Str { $!val ~ 'µ' } } # Is this the right way
我试图像这样重载>>运算符: class A {} multi sub infix:«>>»(A:D $a, Str() $b) is assoc { dd $a; dd $b } my $x = A
在 C++ 中,您可以创建使用特定运算符的模板类 模板化对象和实例化这些对象的类 必须重载该特定运算符才能使其对象与 模板类。例如,insertion BST实现的方法 可能依赖 Nil ) {
有时,我在未重载的方法后面有“overload”关键字。 除了代码的可读性和可维护性之外,这还有我应该注意的其他影响吗? 最佳答案 最大的区别在于,当方法的参数不正确时,错误消息对于非重载方法来说明显
我是一名优秀的程序员,十分优秀!