in kotlin, how to pass back a MutableList where th

2019-04-09 08:34发布

问题:

having a hashMap with List as value defined:

     private var mMap: HashMap<String, List<DataStatus>>? = null

having a function return a hashMap but with the value of MutableList

     fun getDataStatus(response: JSONObject?): HashMap<String, MutableList<DataStatus>> {

          return HashMap<String, MutableList<AccountStatusAlert>>()
     }

when pass the result to the hashMap expecting List it got error:

     mMap = getDataStatus(resp) //<== got error

got error:

Error:(81, 35) Type mismatch: inferred type is HashMap<String, 
MutableList<DataStatus>> but HashMap<String, List<DataStatus>>? was expected

回答1:

You have two solutions depending on your needs.

Cast it

Considering that MutableList is a subclass of List, you can cast it. There's only a problem here: you will lose immutability. If you cast the List back to MutableList, you can modify its content.

mMap = getDataStatus(repo) as HashMap<String, List<String>>

Convert it

In order to maintain immutability on the list, you have to convert each MutableList to an immutable List:

mMap = HashMap<String, List<String>>()
getDataStatus(repo).forEach { (s, list) ->
    mMap?.put(s, list.toList())
}

In this case, if you try to modify the content of a list inside mMap, an exception will be thrown.



回答2:

If you do not plan to put new items in the map after it was returned to you, just declare your variable having a more permissive type:

// prohibits calling members that take List<DataStatus> as a parameter,
// so you can store a HashMap with values of any List subtype, 
// for example of MutableList
private var mMap: HashMap<String, out List<DataStatus>>? = null

or

// prohibits calling mutating methods
// List<DataStatus> already has 'out' variance
private var mMap: Map<String, List<DataStatus>>? = null

If you for some reason need that variable to have exactly that type, then you need to convert or upcast values in the returned map:

mMap = getDataStatus(resp).mapValuesTo(HashMap()) { (_, v) -> v as List<DataStatus> }


回答3:

One great solution is:

private var mMap: Map<String, List<DataStatus>>? = null // Do you 
//really need to have object with interface of HashMap? I don't think so..
mMap = getDataStatus(resp).mapValues { it.value.toList() } 
// add as HashMap<String, List<DataStatus>> if you really need 
//HashMap interface

So, using var + nullable types is not recommended when using Kotlin. Maybe you want follows:

val mMap = mutableMapOf<String, List<DataStatus>()

or immediately:

val mMap = getDataStatus(resp).mapValues {
 it.value.toList()
}