36

Following the documentation, I created an enum class:

enum class BitCount public constructor(val value : Int)
{
  x32(32),
  x64(64)
}

Then, I'm trying to declare a variable in some function:

val bitCount : BitCount = BitCount(32)

But there is a compilation error:

Error:(18, 29) Kotlin: Enum types cannot be instantiated

How do I declare a variable of BitCount type and initialize it from an Int?

Pang
  • 9,564
  • 146
  • 81
  • 122
Ed Pavlov
  • 2,353
  • 2
  • 19
  • 25
  • BTW, you don't have to use the full constructor syntax for simple cases, so the word `constructor` is redundant. It may be done with just `public enum class BitCount(..)` – voddan Jul 24 '15 at 18:38
  • If you still want to create an instance of the Enum given the numeric value, you can (but it is more "find the instance given a numeric value"): http://stackoverflow.com/a/34625163/3679676 – Jayson Minard Jan 06 '16 at 03:33
  • for new comers. read this tutorial on enums in Kotlin. http://developine.com/enum-classes-in-kotlin-example/ – Developine Nov 24 '17 at 12:05
  • All ENUM constants have to be declared inside the enum class definition. What you are trying to do (creating object) is for a regular class, not of ENUM. Refer https://www.tutorialkart.com/kotlin/enum-classes-in-kotlin/ for examples on Kotlin Enum. – arjun Mar 24 '18 at 07:02

4 Answers4

75

As stated in other answers, you can reference any value of the enum that exists by name, but not construct a new one. That does not prevent you from doing something similar to what you were trying...

// wrong, it is a sealed hierarchy, you cannot create random instances
val bitCount : BitCount = BitCount(32)

// correct (assuming you add the code below)
val bitCount = BitCount.from(32)

If you were wanting to find the instance of the enum based on the numeric value 32 then you could scan the values in the following way. Create the enum with a companion object and a from() function:

enum class BitCount(val value : Int)
{
    x16(16),
    x32(32),
    x64(64);

    companion object {
        fun from(findValue: Int): BitCount = BitCount.values().first { it.value == findValue }
    }
}

Then call the function to get a matching existing instance:

val bits = BitCount.from(32) // results in BitCount.x32

Nice and pretty. Alternatively in this case you could create the name of the enum value from the number since you have a predictable relationship between the two, then use BitCount.valueOf(). Here is the new from() function within the companion object.

fun from(findValue: Int): BitCount = BitCount.valueOf("x$findValue")
Jayson Minard
  • 84,842
  • 38
  • 184
  • 227
  • Nice! One might want to use `valueOf`, though; then it looks like we'd overload `valueOf(String)`. – Raphael Mar 24 '17 at 19:43
  • 2
    Variants: 1) `when` over the possible inputs, dealing with `else` properly. 2) Use `firstOrNull` and make the return value of `from` optional. 3) [Preprocess a map](http://stackoverflow.com/a/37795810/539599). – Raphael Mar 24 '17 at 19:46
  • for new comers. read this tutorial on enums in Kotlin. http://developine.com/enum-classes-in-kotlin-example/ – Developine Nov 24 '17 at 12:05
  • 1
    Your "from()" method should be in the Kotlin library! – Guildenstern70 Jan 01 '19 at 10:00
14

Enum instances could be declared only inside enum class declaration.

If you want to create new BitCount just add it as shown below:

enum class BitCount public constructor(val value : Int)
{
    x16(16),
    x32(32),
    x64(64)
}

and use everywhere as BitCount.x16.

Greg Kopff
  • 15,945
  • 12
  • 55
  • 78
user2235698
  • 7,053
  • 1
  • 19
  • 27
8

What about:

enum class BitCount constructor(val value : Int)
{
    x32(32),
    x64(64);

    companion object {
         operator fun invoke(rawValue: Int) = BitCount.values().find { it.rawValue == rawValue }
    }
}

Then you can use it like you proposed:

val bitCount = BitCount(32)

And it will return null if value is not found in enum cases

Angel G. Olloqui
  • 8,045
  • 3
  • 33
  • 31
0

If you really do want to give the ability to construct arbitrary instances, use a value class instead of an enum.

@JvmInline value class BitCount(val value: Int) {
    companion object {
        val x32 = BitCount(32)
        val x64 = BitCount(64)
    }
}

Value classes are always compared by their value, rather than by identity. You can call BitCount(32), but the result will always be the same as the existing x32 instance, as there's only one possible instance with that value.

Using this approach, you can create any BitCount value you like, for example BitCount(31) or BitCount(-1). Use this approach if the set of possible values can vary at runtime or can't be practically represented by listing them all out in the code. Use an enum if you have a small, fixed set of allowed values that are known at compile-time.

Sam
  • 8,330
  • 2
  • 26
  • 51