Kotlin允许命名一个与现有类相同的函数,例如HashSet初始化函数可以像这样实现:
fun <T> HashSet(n : Int, fn: (Int) -> T) = HashSet<T>(n).apply {
repeat(n) {
add(fn(it))
}
}
Run Code Online (Sandbox Code Playgroud)
使用时,它看起来像一个普通的HashSet构造函数:
var real = HashSet<String>()
var fake = HashSet(5) { "Element $it" }
Run Code Online (Sandbox Code Playgroud)
这应该避免或鼓励,为什么?
如果我有一个jar,在类路径上,我已经创建了一个扩展函数,说出String类为了参数的缘故,我在String上有另一个具有相同扩展函数的jar,Kotlin如何解析这两个?
我假设如果两个函数都在同一个包中定义,那么会发生冲突吗?
但如果不同的包,我怎么能区分这两个扩展?
Kotlin具有几个可见性修饰符和扩展功能.文件说明了这一点Extensions are resolved statically.但这对扩展函数中类成员的可见性意味着什么呢?
让我们考虑以下人为的例子:
class A { protected val a = "Foo" }
fun A.ext() { print(a) } //Raises: Cannot access 'a': it is 'protected' in 'A'
class B { val b = "Bar" }
fun B.ext() { print(b) } //Compiles successful
Run Code Online (Sandbox Code Playgroud)
代码不会编译.在扩展类时似乎无法访问受保护的成员.
因此,解决静态意味着扩展函数是在Java中具有类似内容的语法糖:
public static void ext(A receiver){ System.out.print(receiver.a); }
Run Code Online (Sandbox Code Playgroud)
这可以解释为什么受保护的成员无法访问.另一方面,可以this在扩展函数中使用(甚至省略).
那么扩展功能的确切范围是什么?
我知道内联关键字的意思是避免调用功能的调用开销。但是我不知道扩展属性可以用于什么内联?
假设我们有两个名为foo的扩展属性,另一个带有名为bar的内联属性
val Any.foo : Long
get() = Date().time
inline val Any.bar : Long
get() = Date().time
Run Code Online (Sandbox Code Playgroud)
执行其中的任何一个,我们将期望的输出,即当前时间。
该文件的字节码如下:
val Any.foo : Long
get() = Date().time
inline val Any.bar : Long
get() = Date().time
Run Code Online (Sandbox Code Playgroud)
我们可以看到两者相似,但仅在以下几行不同:
foo提取:
LOCALVARIABLE $receiver Ljava/lang/Object; L0 L2 0
MAXSTACK = 2
MAXLOCALS = 1
Run Code Online (Sandbox Code Playgroud)
酒吧摘录:
LOCALVARIABLE $receiver Ljava/lang/Object; L0 L2 0
LOCALVARIABLE $i$f$getBar I L0 L2 1
MAXSTACK = 2
MAXLOCALS = 2
Run Code Online (Sandbox Code Playgroud)
我真的不明白这里发生了什么。有人可以指点我看一下它的行为,或java中的等效行为,或对此的一些用法吗?
编辑
给定编译器将替换内联属性的内容,可以方便地内联每个没有繁重操作的扩展属性。
谢谢
我想访问包含在NavigationView的headerLayout中的TextView.是否可以使用Kotlin android扩展程序访问该视图?我使用了这个方法,但TextView(此处为txtName)始终为null.
这是我的activity_main.xml
<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_splash"
app:menu="@menu/activity_splash_drawer" />
Run Code Online (Sandbox Code Playgroud)
nav_header_splash.xml
<TextView
android:id="@+id/txtName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/txt1"
android:layout_below="@+id/imageView"
android:text="@string/name"
android:textSize="18sp"
android:textColor="@color/white" />
Run Code Online (Sandbox Code Playgroud)
在MainActivity.kt 我已导入
import kotlinx.android.synthetic.main.nav_header_splash.*
Run Code Online (Sandbox Code Playgroud)
在onCreate()Activity类我设置文本就好
txtName.text = "Sample Code"
Run Code Online (Sandbox Code Playgroud)
app文件夹的build.gradle
apply plugin: 'kotlin-android-extensions'
Run Code Online (Sandbox Code Playgroud)
我的项目的build.gradle
classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
Run Code Online (Sandbox Code Playgroud)
我的代码中有错误吗?请帮忙.我是Kotlin的新人.
我是Kotlin的新手,正在尝试制作对象列表的副本。我遇到的问题是,当我更改新副本中的项目时,旧列表也会被更改。这是对象:
class ClassA(var title: String?, var list: ArrayList<ClassB>, var selected: Boolean)
class ClassB(val id: Int, val name: String)
Run Code Online (Sandbox Code Playgroud)
我尝试这样做,但是不起作用:
val oldList:ArrayList<ClassA>
val newList :ArrayList<ClassA> = ArrayList()
newList.addAll(oldList)
Run Code Online (Sandbox Code Playgroud) 假设我有一个Foo带有可空值的简单类String?
data class Foo(
val bar: String?
)
Run Code Online (Sandbox Code Playgroud)
我创建了一个简单的函数 capitalize
fun captitalize(foo: Foo) = when {
foo.bar != null -> runCatching { foo.bar.capitalize() }
else -> ""
}
Run Code Online (Sandbox Code Playgroud)
这很好用,因为尽管编译器推断foo.bar的类型可以为空,但它不能为null。但是后来我决定编写与扩展相同的函数Foo
fun Foo.captitalize2() = when {
bar != null -> runCatching { bar.capitalize() }
else -> ""
}
Run Code Online (Sandbox Code Playgroud)
突然编译器不再能够推断出bar不是null,而IntelliJ告诉我“在类型为null的接收者上仅允许安全(?。)或非null断言(!!。)调用。串?”
谁能解释为什么?
嘿,想要获取T 的类型,但我无法从实例中获取它,我必须从类参数中获取它,该怎么做?
abstract class ViewModelFragment<T : ViewModel>{
protected lateinit var mViewModel: T
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
mViewModel = ViewModelProviders
.of(scope)
.get(getGenericTClass())
// .get(mViewModel.javaClass) // not working either
}
inline fun<reified R> getGenericTClass() = R::class.java
}
Run Code Online (Sandbox Code Playgroud)
现在编译器抱怨
不能使用“T”作为精炼的类类型。请改用 Class。
我尝试使用以下解决方案:https : //stackoverflow.com/a/34463352/2163045但对我不起作用
假设我想将以下代码作为可重用的组件:
fun <T> MutableList<T>.swap(index1: Int, index2: Int) {
val tmp = this[index1] // 'this' corresponds to the list
this[index1] = this[index2]
this[index2] = tmp
}
Run Code Online (Sandbox Code Playgroud)
我想在我的应用程序中的任何地方使用它,如下所示:
val l = mutableListOf(1, 2, 3)
l.swap(0, 2)
Run Code Online (Sandbox Code Playgroud)
如果我错了,请纠正我,但我相信函数扩展声明可以存在于类之外。那么在 Android 应用程序中,我应该把这个声明放在哪里?或者它甚至重要吗?compile 是否只编译代码,而不管扩展在哪里声明并使其可在全局范围内重用,还是必须使其成为类的一部分?
我的Android项目有两个模块:
app
common
Run Code Online (Sandbox Code Playgroud)
在settings.gradle中:
rootProject.name='My project'
include ':app'
include ':common'
Run Code Online (Sandbox Code Playgroud)
在我的 build.gradle 中:
implementation project(':common')
Run Code Online (Sandbox Code Playgroud)
在公共包中,我有StringUtil.kt和下一个扩展函数:
fun String.isEmailValid(): Boolean {
return !TextUtils.isEmpty(this) && android.util.Patterns.EMAIL_ADDRESS.matcher(this).matches()
}
Run Code Online (Sandbox Code Playgroud)
在这个类中我可以使用这样的扩展函数:
val str = ""
str.isEmailValid()
Run Code Online (Sandbox Code Playgroud)
但在app模块中我有课
class RegistrationViewModel(application: Application) : AndroidViewModel(application) {
fun doClickRegistration(email: String?, password: String?, retypePassword: String?) {
val str = ""
str.isEmailValid()
}
}
Run Code Online (Sandbox Code Playgroud)
但现在我得到编译错误:
未解决的参考:isEmailValid