Apakah mungkin untuk memanggil fungsi dengan unaryPlus di kotlin?
Ini adalah pertanyaan lanjutan untuk pertanyaan lain yang saya ajukan kemarin.
Bagaimana cara membuat daftar bersarang menggunakan pola pembangun?
Penghargaan untuk : Pelocho karena memberikan jawaban yang bagus.
Saya menggunakan Tutorial ini untuk membuat pembuat kueri graphQL yang aman:
Yang ingin saya lakukan sekarang adalah menyederhanakan apa yang saya buat. Dan saya tahu bahwa kotlin pasti memiliki beberapa fitur bagus untuk melakukannya.
Sekarang saya harus menjalankan fungsi ketika saya ingin menambahkan entitas ke kueri saya:
fun main() {
events{
title() // I don't like to do () when it is an edge case
}
}
Saya bertanya-tanya apakah mungkin melakukan sesuatu yang berbeda, dan lebih sederhana, seperti:
fun main() {
events{
title // this is much nicer
}
}
Tetapi jika tidak memungkinkan maka tidak apa-apa hanya untuk mengurangi jumlah karakter dengan operator yang kelebihan beban seperti misalnya.unaryPlus
fun main() {
events{
+title // this is also nicer
}
}
Kode saya yang saya miliki sekarang memiliki kelas yang disebut Query
tempat saya meletakkan metode:
operator fun Query.unaryPlus() {
visitEntity(this,{})
}
Tapi sepertinya itu tidak berhasil untuk saya.
Semua kode saya ada di sini.
interface Element {
fun render(builder: StringBuilder, indent: String)
}
@DslMarker //Domain Specific Language
annotation class GraphQLMarker
@GraphQLMarker
abstract class Query(val name: String) : Element {
val children = arrayListOf<Element>()
protected fun <T : Element> visitEntity(entity: T, visit: T.() -> Unit = {}): T {
entity.visit()
children.add(entity)
return entity
}
override fun render(builder: StringBuilder, indent: String) {
builder.append("$indent$name")
if (children.isNotEmpty()) {
builder.append("{\n")
for (c in children) {
c.render(builder, "$indent ") } builder.append("$indent}")
}
builder.append("\n")
}
operator fun Query.unaryPlus() {
visitEntity(this,{})
}
override fun toString(): String {
val builder = StringBuilder()
render(builder, "")
return builder.toString()
}
}
Kemudian saya membuat kelas yang relevan dengan kasus saya
class Filter private constructor(val filters: MutableMap<FilterType, Any>) {
class Builder {
private val filters = mutableMapOf<FilterType, Any>()
fun filters(key: FilterType, value: Any) = apply {
this.filters[key] = value
}
fun build(): Filter {
return Filter(filters)
}
}
}
class EVENTS(private val filter: Filter) : Query("events") {
override fun render(builder: StringBuilder, indent: String) {
builder.append("{$name") if (filter.filters.isNotEmpty()) { builder.append("(" + filter.filters.map { if (it.value is Int || it.value is Long) { it.key.str + ":" + it.value + "," } else { it.key.str + ":\"" + it.value + "\"," } }.joinToString(" ").dropLast(1) + ")") } if (children.isNotEmpty()) { builder.append("{\n") for (c in children) { c.render(builder, "$indent ")
}
builder.append("$indent}")
}
builder.append("\n}")
}
fun title() = visitEntity(TITLE())
fun genre() = visitEntity(GENRE())
fun image() = visitEntity(IMAGE())
fun link() = visitEntity(LINK())
fun other() = visitEntity(OTHER())
fun price() = visitEntity(PRICE())
fun text() = visitEntity(TEXT())
fun tickets() = visitEntity(TICKETS())
fun time() = visitEntity(TIME())
fun location(visit: LOCATION.() -> Unit) = visitEntity(LOCATION(), visit)
}
class TITLE : Query("title")
class GENRE : Query("genre")
class IMAGE : Query("image")
class LINK : Query("link")
class OTHER : Query("other")
class PRICE : Query("price")
class TEXT : Query("text")
class TICKETS : Query("tickets")
class TIME : Query("time")
class LOCATION : Query("location") {
fun area() = visitEntity(AREA())
fun place() = visitEntity(PLACE())
fun address(visit: ADDRESS.() -> Unit) = visitEntity(ADDRESS(), visit)
fun coordinates(visit: COORDINATES.() -> Unit) = visitEntity(COORDINATES(), visit)
}
class AREA : Query("area")
class PLACE : Query("place")
class ADDRESS : Query("address") {
fun city() = visitEntity(CITY())
fun street() = visitEntity(STREET())
fun no() = visitEntity(NO())
fun state() = visitEntity(STATE())
fun zip() = visitEntity(ZIP())
}
class CITY : Query("city")
class STREET : Query("street")
class NO : Query("no")
class STATE : Query("state")
class ZIP : Query("zip")
class COORDINATES : Query("coordinates") {
fun longitude() = visitEntity(LONGITUDE())
fun latitude() = visitEntity(LATITUDE())
}
class LONGITUDE : Query("longitude")
class LATITUDE : Query("latitude")
enum class FilterType(val str: String) {
PLACE("place"),
PRICELT("priceLT"),
PRICEGT("priceGT"),
TIMELT("timestampLT"),
TIMEGT("timestampGT"),
AREA("area"),
TITLE("title"),
GENRE("genre")
}
Beberapa kelas adalah edgecases dan tidak akan bersarang lebih jauh. Jadi saya berpikir apakah mungkin untuk menyederhanakannya sedikit. Dan jika saya dapat menggunakan a unaryPlus
untuk memanggil mereka ketika saya memanggil mereka dari main()
fungsi, jadi saya tidak perlu menulis {}
setelah edgecase sangat tunggal, ketika mereka tidak memiliki sarang menunggu lagi.
fun main(){
events(filter) {
title()
genre()
image()
link()
tickets()
other()
price()
text()
time()
location {
area()
place()
address {
city()
street()
no()
state()
zip()
}
coordinates {
longitude()
latitude()
}
}
}
}
Terima kasih sebelumnya. Semoga harimu menyenangkan!
Jawaban
Ya, Anda dapat menggunakannya unaryPlus
untuk apa pun yang Anda inginkan
Periksa dokumentasi Operator overloading
Di sini Anda memiliki contoh yang berfungsi:
fun main() {
val events = events {
+title
+genre
}
println(events.render())
}
interface Element {
fun render() : String
}
@DslMarker //Domain Specific Language
annotation class GraphQLMarker
@GraphQLMarker
fun events(init: EventBody.() -> Unit): Element {
val events = EventBody()
events.init()
return events
}
class EventBody: Element {
override fun render() =
"events:${elements.joinToString { it.render() }}"
private val elements = mutableListOf<Element>()
operator fun Element.unaryPlus() = elements.add(this)
}
@GraphQLMarker
object title: Element {
override fun render() = "title"
}
@GraphQLMarker
object genre: Element {
override fun render() = "genre"
}
keluaran yang mana
events:title, genre