Kotlin:无法找到表达式,因为找不到函数invoke()

时间:2018-10-31 15:05:15

标签: kotlin

我正在尝试构建一个用于实现Google地图的应用。由于某种原因,我收到错误消息,因为找不到函数invoke(),因此无法调用表达式。我不知道该如何解决,也许你们中的一个可以帮助您?

    package com.example.maxs.kotlinnearbyv2

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import com.example.maxs.kotlinnearbyv2.Common.Common
import com.example.maxs.kotlinnearbyv2.Model.MyPlaces
import com.example.maxs.kotlinnearbyv2.Remote.IGoogleAPIService
import com.google.android.gms.maps.*
import com.google.android.gms.maps.model.BitmapDescriptorFactory

import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.MarkerOptions
import kotlinx.android.synthetic.main.activity_maps.*
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response

class MapsActivity : AppCompatActivity(), OnMapReadyCallback {

private lateinit var mMap: GoogleMap

private var latitude:Double=0.toDouble()
private var longitude:Double=0.toDouble()

lateinit var mService:IGoogleAPIService

internal var currentPlace: MyPlaces?=null

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_maps)
    // Obtain the SupportMapFragment and get notified when the map is ready to be used.
    val mapFragment = supportFragmentManager
        .findFragmentById(R.id.map) as SupportMapFragment
    mapFragment.getMapAsync(this)

    //Init Service
    mService = Common.googleApiService

    bottom_navigation_view.setOnNavigationItemReselectedListener {item ->
        when(item.itemId)
        {
            R.id.action_hospital -> nearByPlace("hospital")
            R.id.action_restaurant -> nearByPlace("restaurant")
            R.id.action_market -> nearByPlace("market")
            R.id.action_school -> nearByPlace("school")
        }
    }
}

private fun nearByPlace(typePlace: String) {

    //Clear all marker on Map
    mMap.clear()
    //build URL request base on location
    val url = getUrl(latitude,longitude, typePlace)

    mService.getNearByPlaces(url)
        .enqueue(object : Callback<MyPlaces>{
            override fun onResponse(call: Call<MyPlaces>, response: Response<MyPlaces>) {

                currentPlace = response.body()

                if(response!!.isSuccessful)
                {
                    for(i in 0 until response!!.body()!!.results!!.size)
                    {
                        val markerOptions=MarkerOptions()
                        val googlePlace = response.body().results!!(i)
                        val lat = googlePlace.geometry!!.location!!.lat
                        val lng = googlePlace.geometry!!.location!!.lng
                        val placeName = googlePlace.name
                        val latLng = LatLng(lat, lng)

                        markerOptions.position(latLng)
                        markerOptions.title(placeName)
                        if (typePlace.equals("hospital"))
                            markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_local_hospital_black_24dp))
                        else if (typePlace.equals("market"))
                            markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_shopping_cart_black_24dp))
                        else if (typePlace.equals("restaurant"))
                            markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_restaurant_black_24dp))
                        else if (typePlace.equals("school"))
                            markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_school_black_24dp))
                        else
                            markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE))

                        markerOptions.snippet(i.toString())

                        //add marker to map
                        mMap!!.addMarker(markerOptions)


                    }
                    //move camera
                    mMap!!.moveCamera(CameraUpdateFactory.newLatLng(LatLng(latitude, longitude)))
                    mMap!!.animateCamera(CameraUpdateFactory.zoomTo(15.0f))
                }
            }

            override fun onFailure(call: Call<MyPlaces>, t: Throwable) {
                Toast.makeText(baseContext, ""+t!!.message,Toast.LENGTH_SHORT).show()
            }

        })
}

private fun getUrl(latitude: Double, longitude: Double, typePlace: String): String {

    val googlePlaceUrl = StringBuilder("https://maps.googleapis.com/maps/api/place/nearbysearch/json")
    googlePlaceUrl.append("?location=$latitude,$longitude")
    googlePlaceUrl.append("&radius=10000") //10 km
    googlePlaceUrl.append("&type=$typePlace")
    googlePlaceUrl.append("&key=")

    Log.d("URL_DEBUG", googlePlaceUrl.toString())
    return googlePlaceUrl.toString()
}

/**
 * Manipulates the map once available.
 * This callback is triggered when the map is ready to be used.
 * This is where we can add markers or lines, add listeners or move the camera. In this case,
 * we just add a marker near Sydney, Australia.
 * If Google Play services is not installed on the device, the user will be prompted to install
 * it inside the SupportMapFragment. This method will only be triggered once the user has
 * installed Google Play services and returned to the app.
 */
override fun onMapReady(googleMap: GoogleMap) {
    mMap = googleMap

    // Add a marker in Sydney and move the camera
    val barbier = LatLng(52.391274, 6.449712)
    mMap.addMarker(MarkerOptions().position(barbier).title("Marker in Barbier"))
    mMap.moveCamera(CameraUpdateFactory.newLatLng(barbier))
    mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(barbier, 15.0f))
}
}

我似乎找不到任何解决方案,我可能想办法很难… 错误出现在response.body()!!。results !!(i)

val googlePlace = response.body().results!!(i)

肯定现在让我发疯了。

2 个答案:

答案 0 :(得分:2)

要访问数组或列表中的元素,请使用方括号,例如:

function write(isbn, title, author, issued) {
  const fs = require(['fs'], function (fs){  
  const data = fs.readFileSync('js/book.json');
  let jsonStr = data.toString();
  const obj = JSON.parse(jsonStr);

  obj.books.push({
    isbn,
    title,
    author,
    issued,
  });
  jsonStr = JSON.stringify(obj);
  console.log(jsonStr);
  fs.truncate('js/book.json', 0, () => {
    fs.writeFile('js/book.json', jsonStr, (err) => {
      if (err) {
        throw new Error(`Error writing file: ${err}`);
      }
    });
  });
  });
}

关于错误消息:Kotlin假设您没有提供invoke operator。您可能需要阅读invoke-operator的优点。有时它非常方便。但是对于您的问题,方括号就足够了。

作为(更多)补充说明:不要用大量的array[i] list[i] // or list.get(i) results!![i] 来编写代码,而是首先尝试确定!!可能是什么,如果没有,则忽略其余的内容不能满足您的需求,例如:

null

只是一个开始...您可能然后想进一步简化事情...只要可能就省略response?.also { if (it.isSuccessful) { it.body()?.results?.forEach { //... } } } ...您可能还想读一下null safety in Kotlin,也许还想smart casts

您的!!-条件也可以完美地替换为when,例如:

typePlace.equals(...

when(typePlace) { "hospital" -> ... "market" -> ... let结合使用甚至可以进一步减少您的代码,但这可能是另一个故事,更适合code review

答案 1 :(得分:1)

如Roland所述,()是调用运算符,而[]是索引运算符。 ()用于以下功能:

fun demo(func: (i: Int) -> Unit){
    // These are identical
    func(1)
    func.invoke(1)
}

[]index operator,这就是您要在此处应用的内容。

它可用于具有operator fun get(args)

的任何类
class Demo {
    // These don't actually need a return type either. Or any arguments at all. 
    // If this was an int-containing class (i.e. a List), this would be the conventional declaration
    operator fun get(index: Int) : Int {
        return 0 // Obviously with an actual return value. 
    }

    // But they don't have to. They can have multiple, or no arguments. 
    operator fun get(index: Int, fallback: Int) : Int{
        return fallback
    }
}

fun test(){
    val demo = Demo()
    //Depending on arguments, the use is different. Single-arg is basic, and traditional:
    val value = demo[12];
    // But the multi-arg one can be useful depending on the class.
    val value2 = demo[12, 3];
}

我知道您没有要求声明这些内容,但是代码是我的观点的一部分:

  • 将索引运算符应用于具有operator fun get,具有任意数量的输入参数的任何类
  • 列表,地图和数组具有此方法。

因此,您要使用[index],而不是(index)。另外,您可以使用方法,并直接使用.get(index)。如果要使用空安全调用(?.),则必须使用.get(index)

此外,与使用null断言相比,通常应该更喜欢null安全的调用,可以选择将它们与?.let{ }?.forEach { }或类似方法组合使用。首先,它有点违反了Kotlin的核心部分之一:空安全性。其次,如果它曾经为null,则该应用程序将崩溃,而不是优雅地告诉用户“出了点问题”。我不熟悉您正在使用的库,因此,老实说,我不确定什么时候为null,即使成功也可以为null。

对于letforEach,当您具有可空性时,它们将更易于使用。考虑一下:

someNullableIterable?.forEach {
    // Only invoked if the iterable isn't null
}

相比:

if(someNullableIterable!= null){
    for(item in someNullableIterable!!) { // Needs !! if the variable is global, and it's a var and not a val. 
        // Foo bar
    }
}

也有很多类似的功能,如果您还需要使用索引,则可以使用forEachIndexed。但是仅使用forEach(或者forEachIndexed)将缩短您的某些代码,并更好地使您处理可空性。