क्या कोटलिन में एक अनार्यप्लस के साथ एक समारोह को लागू करना संभव है?
यह एक और सवाल है जो मैंने कल पूछा था।
मैं बिल्डर पैटर्न का उपयोग करके नेस्टेड सूची कैसे बना सकता हूं?
श्रेय: अच्छा जवाब देने के लिए पेल्लो ।
मैंने इस ट्यूटोरियल का उपयोग एक प्रकार का सुरक्षित ग्राफक्यूएल क्वेरी बिल्डर करने के लिए किया है:
अब मैं जो करना चाहता हूं उसे सरल बनाना है और मुझे पता है कि कोटलिन के पास ऐसा करने के लिए कुछ अच्छी विशेषताएं होनी चाहिए।
जब मैं अपनी क्वेरी में एक इकाई जोड़ना चाहता हूँ, तो अभी मुझे कार्य करना है:
fun main() {
events{
title() // I don't like to do () when it is an edge case
}
}
मैं सोच रहा हूं कि क्या यह कुछ अलग करने के लिए पॉसिबल है, और अधिक सरल है, जैसे:
fun main() {
events{
title // this is much nicer
}
}
लेकिन अगर यह संभव नहीं है, तो यह ठीक है जैसे कि एक ऑपरेटर के साथ पात्रों की मात्रा को कम करना जैसे कि ओवरलोडिंग ।unaryPlus
fun main() {
events{
+title // this is also nicer
}
}
मेरा कोड जो अब मेरे पास है, एक कक्षा कहलाती है Queryजहाँ मैंने विधि रखी है:
operator fun Query.unaryPlus() {
visitEntity(this,{})
}
लेकिन यह मेरे लिए काम नहीं करता है।
मेरा सारा कोड यहाँ है
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()
}
}
फिर मैंने अपने मामले के लिए प्रासंगिक कक्षाएं बनाईं
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")
}
कुछ वर्ग edgecases हैं और अपने आप को और नीचे नहीं घोंसला बनाएंगे । इसलिए मैं सोच रहा था कि क्या इसे थोड़ा सरल करना संभव है। और अगर मैं unaryPlusउन्हें main()फ़ंक्शन से कॉल करने के लिए उन्हें उपयोग करने के लिए उपयोग कर सकता हूं , तो मुझे {}बहुत एकल edececase के बाद लिखना नहीं है , जब उनके पास किसी भी तरह के घोंसले के शिकार नहीं होते हैं
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()
}
}
}
}
पहले ही, आपका बहुत धन्यवाद। आपका दिन शुभ हो!
जवाब
हां, आप unaryPlusजो चाहें उपयोग कर सकते हैं
ऑपरेटर ओवरलोडिंग दस्तावेज की जाँच करें
यहाँ आपके पास एक काम करने का उदाहरण है:
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"
}
जो आउटपुट देता है
events:title, genre