最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Kotlin Secondary constructor without duplicating operation - Stack Overflow

programmeradmin1浏览0评论

Given the Kotlin data class:

data class Entity(
    val uuidId: UUID?,
    val stringId: String?,
    val stuff: String
) {
    constructor(id: String, stuff: String) : this(
        uuidId = try { UUID.fromString(id) } catch(_:Throwable) { null },
        stringId = try { UUID.fromString(id); null } catch(_:Throwable) { id },
        stuff = stuff
    )
}

Can I avoid doing UUID.fromString(id) twice?

Given the Kotlin data class:

data class Entity(
    val uuidId: UUID?,
    val stringId: String?,
    val stuff: String
) {
    constructor(id: String, stuff: String) : this(
        uuidId = try { UUID.fromString(id) } catch(_:Throwable) { null },
        stringId = try { UUID.fromString(id); null } catch(_:Throwable) { id },
        stuff = stuff
    )
}

Can I avoid doing UUID.fromString(id) twice?

Share Improve this question asked Mar 12 at 22:21 KurtKurt 5551 gold badge6 silver badges16 bronze badges 2
  • Unless your Entity class reflects a DB row, for example, consider redesigning it as an interface, and implement it with a class that holds a String and one that holds a UUID. – Klitos Kyriacou Commented Mar 13 at 9:22
  • @KlitosKyriacou. It is an entity. – Kurt Commented Mar 13 at 13:21
Add a comment  | 

2 Answers 2

Reset to default 3

Declaring a local variable in a secondary constructor might have helped, but you cannot declare local variables inside a secondary constructor.
There is a discussion on a similar topic in the Kotlin forum Secondary constructor initiation logic on data class

I would suggest to add a companion object with an invoke function:

data class Entity(
    val uuidId: UUID?,
    val stringId: String?,
    val stuff: String
) {
    companion object {
        operator fun invoke(id: String, stuff: String): Entity {
            val uuid = try { UUID.fromString(id) } catch (_: Throwable) { null }
            val stringId = if (uuid != null) null else id
            return Entity(uuid, stringId, stuff)
        }
    }
}

@Test
fun `create entity using invoke function`() {
    val entityWithUuid = Entity("123e4567-e89b-12d3-a456-426614174000", "staff_1")
    val entityWithStringId = Entity("my_id", "staff_2")
    // Entity(uuidId=123e4567-e89b-12d3-a456-426614174000, stringId=null, stuff=staff_1)
    println(entityWithUuid)
    // Entity(uuidId=null, stringId=my_id, stuff=staff_2)
    println(entityWithStringId)
}

Another approach is to define an an explicit factory method inside companion object

companion object {
    fun create(id: String, stuff: String): Entity {
        // same body as in invoke
    }
}

And then create an object

val entity = Entity.create("123e4567-e89b-12d3-a456-426614174000", "staff_1")

Here is an invoke function with minor changes, maybe you'll find them handy

operator fun invoke(id: String, stuff: String): Entity = try {
    Entity(UUID.fromString(id), null, stuff)
} catch (_: Throwable) {
    Entity(null, id, stuff)
}

I would have it go through another secondary constructor - one that takes a Pair<UUID?, String?>.

private constructor(idPair: Pair<UUID?, String?>, stuff: String): this(
    uuidId = idPair.first,
    stringId = idPair.second,
    stuff = stuff,
)

Then you can use various scope functions in the other secondary constructor to construct the Pair.

constructor(id: String, stuff: String) : this(
    idPair = id.runCatching { UUID.fromString(this) }.let { result ->
        Pair(result.getOrNull(), id.takeIf { result.isFailure })
    },
    stuff = stuff
)
发布评论

评论列表(0)

  1. 暂无评论