I would like to initialize enum by its associated value.
My enum:
enum class DirectionSwiped(raw: Int){
LEFT(4),
RIGHT(8);
}
I would like to initialize it as such:
val direction = DirectionSwiped(raw: 4)
But I get this error:
Enum type cannot be instantiated
Why is this happening? In Swift, this functionality works like this:
enum Direction: Int {
case right = 2
}
let direction = Direction(rawValue: 2)
How can I make it work in Kotlin?
Yes you can
enum class DirectionSwiped(val raw: Int){
LEFT(4),
RIGHT(8);
}
val left = DirectionSwiped.LEFT
val right = DirectionSwiped.RIGHT
val leftRaw = DirectionSwiped.LEFT.raw
val rightRaw = DirectionSwiped.LEFT.raw
val fromRaw = DirectionSwiped.values().firstOrNull { it.raw == 5 }
This would be the correct way to access the instances of the enum class
What you are trying to do is create a new instance outside the definition site, which is not possible for enum or sealed classes, that's why the error says the constructor is private
As the error says, you cannot instantiate enums in Kotlin. A possible workaround would be to use a map and 2 helper methods to get enum values from raw values and vice versa:
enum class DirectionSwiped {
LEFT,
RIGHT;
fun toRaw() = enumToRaw[this]
companion object {
val rawToEnum = mapOf(
4 to LEFT,
8 to RIGHT
)
val enumToRaw = rawToEnum.entries.associate{(k,v)-> v to k}
fun ofRaw(raw: Int): DirectionSwiped? = rawToEnum[raw]
}
}
Usage:
val direction = DirectionSwiped.ofRaw(4) // LEFT
val raw = DirectionSwiped.LEFT.toRaw() // 4
Related
Just simple kotlin code to demo Adapter Pattern in Gang of Four Design Pattern. I have a presentation today about this but i can't done it. So sad. I don't want to add much details but they don't allow me to post without much details.
Exception:
Exception in thread "main" java.lang.ClassFormatError: Duplicate method name "getRadius" with signature "()I" in class file RoundHole
at java.lang.ClassLoader.defineClass1 (ClassLoader.java:-2)
at java.lang.ClassLoader.defineClass (ClassLoader.java:756)
at java.security.SecureClassLoader.defineClass (SecureClassLoader.java:142)
Code:
interface WorkingWithRound {
fun getRadius(): Int
}
open class RoundPeg(val radius: Int = 0): WorkingWithRound {
override fun getRadius() = radius
}
class RoundHole(val radius: Int = 0): WorkingWithRound {
override fun getRadius() = radius
fun fit(peg: RoundPeg) {
println(getRadius() >= peg.getRadius())
}
}
class SquarePeg(val width: Int = 0)
class SquarePegAdapter(val speg: SquarePeg): RoundPeg() {
override fun getRadius() = (speg.width / 2 * 1.4).toInt()
}
fun main() {
val hole = RoundHole(5)
val rpeg = RoundPeg(5)
hole.fit(rpeg)
val small_sqpeg = SquarePeg(5)
val large_sqpeg = SquarePeg(10)
//hole.fit(small_sqpeg) // this won't compile (incompatible types)
val small_sqpeg_adapter = SquarePegAdapter(small_sqpeg)
val large_sqpeg_adapter = SquarePegAdapter(large_sqpeg)
hole.fit(small_sqpeg_adapter) // true
hole.fit(large_sqpeg_adapter) // false
}
Kotlin generates getter method for instance variables, hence the error. Couple of options to fix the issue
Make radius variable private
open class RoundPeg(private val radius: Int = 0): WorkingWithRound
Mark radius with #JvmField to instruct compiler not to generate any getter
class RoundHole(#JvmField val radius: Int = 0): WorkingWithRound
I think this would be simpler (as well as avoiding the compilation problems) if the interface defined a property, rather than a getter method:
interface WorkingWithRound {
val radius: Int
}
That compiles down to pretty much the same bytecode; but the intent is clearer, and it can then be implemented directly in the constructors:
open class RoundPeg(override val radius: Int = 0): WorkingWithRound
class RoundHole(override val radius: Int = 0): WorkingWithRound {
fun fit(peg: RoundPeg) {
println(radius >= peg.radius)
}
}
The SquarePegAdapter can be simplified, as it no longer needs to store the speg value, but can simply use it as an initialiser for the property:
class SquarePegAdapter(speg: SquarePeg): RoundPeg() {
override val radius = (speg.width / 2 * 1.4).toInt()
}
And the rest of the code needs no changes.
Say I have this data class in Kotlin:
#Document(collection = Approval.COLLECTION)
data class Approval(
#Id
val id: String,
val detailId: <UNSURE HERE>
) {
companion object {
const val COLLECTION: String = "approval"
}
}
That detailID can either be a String or an object like so:
data class AIDConfiguration(
val sId: String,
val cId: String
)
However how do go about setting that type - as I can't use something like
val detailId: AIDConfiguration | String
I thought maybe make an interface, but not sure any syntax of getting that to be just a String
interface ParentConfiguration
data class AIDConfiguration(
val sId: String,
val cId: String
): ParentConfiguration
And then
val detailId: ParentConfiguration
Any help appreciated.
Thanks.
One way could be:
val detailId: Any
This is loose cause it will allow any type to be assigned to detailId.
So before usage you would have to check for the type.
fun useConfig(detailId: Any) {
if (detailId is AIDConfiguration) {
//Use detailId.sId and detailId.cId. Compiler smart casts to AIDConfiguration
} else if (detailId is String)
//Use detailId. Compiler will smart cast to String
} else {
//throw some exception here.
}
}
You might want to use some validations when setting the configuration as well. Check whether the type is AIDConfiguration or String.
A little more tighter would be to have a parent configuration class. Such as ParentConfiguration and have AIDConfiguration and StringConfiguration as subclasses.
So then it becomes:
interface ParentConfiguration
data class AIDConfiguration(
val sId: String,
val cId: String
): ParentConfiguration
data class StringConfiguration(
val conf: String
): ParentConfiguration
data class Approval(
val id: String,
val detailId: ParentConfiguration
)
val stringConfigApproval = Approval(id = "Test1", detailId = StringConfiguration("String Conf"))
val aidConfApproval = Approval(id = "Test2", detailId = AIDConfiguration(sId = "SID", cId = "CID"))
Would recommend checking out the kotlin docs.
https://kotlinlang.org/docs/tutorials/kotlin-for-py/inheritance.html
https://kotlinlang.org/docs/reference/typecasts.html
Kotlin being a statically typed language, you can't just specify multiple types. An interface is a good option to do so, but since String is not implemented by you, you cannot change its signature.
One of the work around should be to use Either like this:
sealed class Either<out L, out R> {
data class Left<out L>(val a: L) : Either<L, Nothing>()
data class Right<out R>(val b: R) : Either<Nothing, R>()
/**
* Returns true if this is a Right, false otherwise.
* #see Right
*/
val isRight get() = this is Right<R>
/**
* Returns true if this is a Left, false otherwise.
* #see Left
*/
val isLeft get() = this is Left<L>
/**
* Applies fnL if this is a Left or fnR if this is a Right.
* #see Left
* #see Right
*/
fun fold(fnL: (L) -> Any, fnR: (R) -> Any): Any =
when (this) {
is Left -> fnL(a)
is Right -> fnR(b)
}
}
And then specify your variable like this:
val detailId: Either<AIDConfiguration, String>
And when you want to do some specific operation, just call the fold method like:
detailId.fold({ /* use $it as AIDConfiguration */ }, { /* use $it as String */ })
EDIT: You could also make aliases for your purpose in your projects for better readability check https://kotlinlang.org/docs/reference/type-aliases.html
I have a class that has a property whose type is KMutableVar1. The objects of that class have a variable assigned to a reflection of another class's property. I have a function that is supposed take in an object of the first class and uses its variable of type KMutableVar1 to determine which property of an object of the second class to edit.
jeez that paragraph is awful im so so sorry ><
I have already tried assigning the object's KMutableVar1 variable to another variable and then trying to tie that variable to an object using dot notation, but that variable name isn't in the primary constructor for the class and thus an error occurs.
class Thing(var amount: Int, var id: Int){
fun editAttributes(object: Thing, editor: RemoteEdit){
//My initial thought here was to do the following:
var editing = editor.attributeToEdit
object.editing = editor.newValue
//But this raises an error since class 'thing' has no attribute 'editing'
}
}
var bananas = Thing(amount = 12, id = 21)
class RemoteEdit(var attributeToEdit: KMutableVar1, var newValue: Int)
var remoteEditor = RemoteEdit(attributeToEdit = Thing::amount, newValue = 23)
My intent is for the function to change bananas.amount to 23.
Sorry, I'm not fully understanding why you need it but it will work I guess:
import kotlin.reflect.KMutableProperty1
class Thing(var amount: Int, var id: Int) {
fun editAttributes(editor: RemoteEdit) {
val editing = editor.attributeToEdit
editing.set(this, editor.newValue)
}
}
class RemoteEdit(var attributeToEdit: KMutableProperty1<Thing, Int>, var newValue: Int)
fun main() {
val bananas = Thing(amount = 12, id = 21)
val remoteEditor = RemoteEdit(attributeToEdit = Thing::amount, newValue = 23)
bananas.editAttributes(remoteEditor)
println(bananas.amount) // prints 23
}
I have a feeling this might be an XY problem because there are so many unusual things going on in your code. Why would the implementation of changing the property value through reflection be in the class that's being edited?
I suppose if there is some reason you need to be able to pass these parameters for editing around, you would need a class, but then it makes sense for it to implement the function for using it by itself:
class RemoteEdit<T, R>(var attributeToEdit: KMutableProperty1<T, R>, var newValue: R) {
fun execute(item: T) {
attributeToEdit.set(item, newValue)
}
}
val bananas = Thing(amount = 12, id = 21)
val edit23 = RemoteEdit(Thing::amount, 23)
edit23.execute(bananas)
If you don't need to pass these around, all you need is a top level function:
fun <T, R> editProperty(item: T, attributeToEdit: KMutableProperty1<T, R>, newValue: R) =
attributeToEdit.set(item, newValue)
val bananas = Thing(amount = 12, id = 21)
editProperty(bananas, Thing::amount, 23)
I have this enum:
enum class Types(val value: Int) {
FOO(1)
BAR(2)
FOO_BAR(3)
}
How do I create an instance of that enum using an Int?
I tried doing something like this:
val type = Types.valueOf(1)
And I get the error:
Integer literal does not conform to the expected type String
enum class Types(val value: Int) {
FOO(1),
BAR(2),
FOO_BAR(3);
companion object {
fun fromInt(value: Int) = Types.values().first { it.value == value }
}
}
You may want to add a safety check for the range and return null.
Enum#valueOf is based on name. Which means in order to use that, you'd need to use valueof("FOO"). The valueof method consequently takes a String, which explains the error. A String isn't an Int, and types matter. The reason I mentioned what it does too, is so you know this isn't the method you're looking for.
If you want to grab one based on an int value, you need to define your own function to do so. You can get the values in an enum using values(), which returns an Array<Types> in this case. You can use firstOrNull as a safe approach, or first if you prefer an exception over null.
So add a companion object (which are static relative to the enum, so you can call Types.getByValue(1234) (Types.COMPANION.getByValue(1234) from Java) over Types.FOO.getByValue(1234).
companion object {
private val VALUES = values()
fun getByValue(value: Int) = VALUES.firstOrNull { it.value == value }
}
values() returns a new Array every time it's called, which means you should cache it locally to avoid re-creating one every single time you call getByValue. If you call values() when the method is called, you risk re-creating it repeatedly (depending on how many times you actually call it though), which is a waste of memory.
Admittedly, and as discussed in the comments, this may be an insignificant optimization, depending on your use. This means you can also do:
companion object {
fun getByValue(value: Int) = values().firstOrNull { it.value == value }
}
if that's something you'd prefer for readability or some other reason.
The function could also be expanded and check based on multiple parameters, if that's something you want to do. These types of functions aren't limited to one argument.
If you are using integer value only to maintain order, which you need to access correct value, then you don't need any extra code. You can use build in value ordinal. Ordinal represents position of value in enum declaration.
Here is an example:
enum class Types {
FOO, //Types.FOO.ordinal == 0 also position == 0
BAR, //Types.BAR.ordinal == 1 also position == 1
FOO_BAR //Types.FOO_BAR.ordinal == 2 also position == 2
}
You can access ordinal value simply calling:
Types.FOO.ordinal
To get correct value of enum you can simply call:
Types.values()[0] //Returns FOO
Types.values()[1] //Returns BAR
Types.values()[2] //Returns FOO_BAR
Types.values() returns enum values in order accordingly to declaration.
Summary:
Types.values(Types.FOO.ordinal) == Types.FOO //This is true
If integer values don't match order (int_value != enum.ordinal) or you are using different type (string, float...), than you need to iterate and compare your custom values as it was already mentioned in this thread.
It really depends on what you actually want to do.
If you need a specific hardcoded enum value, then you can directly use Types.FOO
If you are receiving the value dynamically from somewhere else in your code, you should try to use the enum type directly in order not to have to perform this kind of conversions
If you are receiving the value from a webservice, there should be something in your deserialization tool to allow this kind of conversion (like Jackson's #JsonValue)
If you want to get the enum value based on one of its properties (like the value property here), then I'm afraid you'll have to implement your own conversion method, as #Zoe pointed out.
One way to implement this custom conversion is by adding a companion object with the conversion method:
enum class Types(val value: Int) {
FOO(1),
BAR(2),
FOO_BAR(3);
companion object {
private val types = values().associate { it.value to it }
fun findByValue(value: Int): Types? = types[value]
}
}
Companion objects in Kotlin are meant to contain members that belong to the class but that are not tied to any instance (like Java's static members).
Implementing the method there allows you to access your value by calling:
var bar = Types.findByValue(2) ?: error("No Types enum value found for 2")
Note that the returned value is nullable, to account for the possibility that no enum value corresponds to the parameter that was passed in. You can use the elvis operator ?: to handle that case with an error or a default value.
If you hate declaring for each enum type a companion object{ ... } to achieve EMotorcycleType.fromInt(...). Here's a solution for you.
EnumCaster object:
object EnumCaster {
inline fun <reified E : Enum<E>> fromInt(value: Int): E {
return enumValues<E>().first { it.toString().toInt() == value }
}
}
Enum example:
enum class EMotorcycleType(val value: Int){
Unknown(0),
Sport(1),
SportTouring(2),
Touring(3),
Naked(4),
Enduro(5),
SuperMoto(6),
Chopper(7),
CafeRacer(8),
.....
Count(9999);
override fun toString(): String = value.toString()
}
Usage example 1: Kotlin enum to jni and back
fun getType(): EMotorcycleType = EnumCaster.fromInt(nGetType())
private external fun nGetType(): Int
fun setType(type: EMotorcycleType) = nSetType(type.value)
private external fun nSetType(value: Int)
---- or ----
var type : EMotorcycleType
get() = EnumCaster.fromInt(nGetType())
set(value) = nSetType(value.value)
private external fun nGetType(): Int
private external fun nSetType(value: Int)
Usage example 2: Assign to val
val type = EnumCaster.fromInt<EMotorcycleType>(aValidTypeIntValue)
val typeTwo : EMotorcycleType = EnumCaster.fromInt(anotherValidTypeIntValue)
A naive way can be:
enum class Types(val value: Int) {
FOO(1),
BAR(2),
FOO_BAR(3);
companion object {
fun valueOf(value: Int) = Types.values().find { it.value == value }
}
}
Then you can use
var bar = Types.valueOf(2)
Protocol orientated way with type-safety
interface RawRepresentable<T> {
val rawValue: T
}
inline fun <reified E, T> valueOf(value: T): E? where E : Enum<E>, E: RawRepresentable<T> {
return enumValues<E>().firstOrNull { it.rawValue == value }
}
enum class Types(override val rawValue: Int): RawRepresentable<Int> {
FOO(1),
BAR(2),
FOO_BAR(3);
}
Usage
val type = valueOf<Type>(2) // BAR(2)
You can use it on non-integer type, too.
I would build the 'reverse' map ahead of time. Probably not a big improvement, but also not much code.
enum class Test(val value: Int) {
A(1),
B(2);
companion object {
val reverseValues: Map<Int, Test> = values().associate { it.value to it }
fun valueFrom(i: Int): Test = reverseValues[i]!!
}
}
Edit: map...toMap() changed to associate per #hotkey's suggestion.
try this...
companion object{
fun FromInt(v:Int):Type{
return Type::class.java.constructors[0].newInstance(v) as Type
}
}
This is for anyone looking for getting the enum from its ordinal or index integer.
enum class MyEnum { RED, GREEN, BLUE }
MyEnum.values()[1] // GREEN
Another solution and its variations:
inline fun <reified T : Enum<T>> enumFromIndex(i: Int) = enumValues<T>()[i]
enumFromIndex<MyEnum>(1) // GREEN
inline fun <reified T : Enum<T>> enumFromIndex(i: Int) = enumValues<T>().getOrNull(i)
enumFromIndex<MyEnum>(3) ?: MyEnum.RED // RED
inline fun <reified T : Enum<T>> enumFromIndex(i: Int, default: T) =
enumValues<T>().getOrElse(i) { default }
enumFromIndex(2, MyEnum.RED) // BLUE
It is an adapted version of another answer. Also, thanks to Miha_x64 for this answer.
Another option...
enum class Types(val code: Int) {
FOO(1),
BAR(2),
FOO_BAR(3);
companion object {
val map = values().associate { it.code to it }
// Get Type by code with check existing codes and default
fun getByCode(code: Int, typeDefault_param: Types = FOO): Types {
return map[code] ?: typeDefault_param
}
}
}
fun main() {
println("get 3: ${Types.getByCode(3)}")
println("get 10: ${Types.getByCode(10)}")
}
get 3: FOO_BAR
get 10: FOO
Like the title says:
class Answers {
enum class Answer(text: String) {
YES("Yes."),
No("No."),
MAYBE("Maybe."),
AGAIN("Ask again.")
}
val answers = Answer.values()
val rand = Random()
fun genAnswer ():String {
val n = rand.nextInt(3)+1
// return Answer[answers[n]].text
}
}
I want to pick an enum element randomly and return its text property. However, it seems I can't use its value to retrieve the element.
You can get a random enum value by doing:
val randomAnswer = Answer.values().toList().shuffled().first().text
Keep in mind that it goes for convenience over performance.
Remember to expose the text property with val. For now, it's just a constructor param:
enum class Answer(val text: String)
Answer.values().random() will do the job for you in Kotlin.
When you write val/var within the constructor for a param, it declares a property inside the class. When you do not write it, it is simply a parameter passed to the primary constructor. So just add val to the constructor param text which will make it a property with a getter and above program will work..
import java.util.*
class Answers {
enum class Answer(val text: String) {
YES("Yes."),
No("No."),
MAYBE("Maybe."),
AGAIN("Ask again.")
}
val answers: Array<Answer> = Answer.values()
val rand = Random()
fun genAnswer ():String {
val n = rand.nextInt(3)+1
return answers[n].text
}
}
fun main(String: Array<String>) {
print(Answers().genAnswer())
}
I use this generic functions for any type of enum
/**
* return random enum value of enum class T
*/
inline fun <reified T : Enum<T>> randomEnum(): T {
val enumValues: Array<T> = enumValues()
return enumValues[(0 until enumValues.size).random()]
}
/**
* return random Int from start to end of range
*/
fun IntRange.random(): Int =
Random().nextInt((endInclusive + 1) - start) + start
I had a Enum SupportedLocale with values for languages
I did it in 2 steps
Get a list of values for enum:
val languages: Array<SupportedLocale> = SupportedLocale.values()
Now select random value using ordinate position
val randomLocale = languages[Random().nextInt(languages.size)]
An easy solution that I have used is
enum class OPERATOR(val symbol:String){MULTIPLY("*"),DIVIDE("/"),ADD("+"),SUBTRACT("-"),REMINDER("-")}
private fun getRandomOperator():String{
val limit=OPERATOR.values().size-1
return OPERATOR.values()[IntRange(0,limit).random()].symbol
}