Kotlin 笔记 -- Kotlin 语言特性的理解(一)

news2024/10/7 16:44:15

函数引用、匿名函数、lambda表达式、inline函数的理解

在这里插入图片描述

  • 双冒号对函数进行引用的本质是生成一个函数对象
  • 只有函数对象才拥有invoke()方法,而函数是没有这个方法的
  • kotlin中函数有自己的类型,但是函数本身不是对象,因此要引用函数类型就必须通过双冒号的方式将函数转换成一个对象,这样之后才能拿这个对象进行赋值

在这里插入图片描述

  • 匿名函数是一个对象,它不是函数
  • 匿名函数跟双冒号引用函数是一种东西
  • 而 lambda 表达式是一种特殊的匿名函数对象,它可以省略参数和调用者括号等,更加方便而已
  • 因为匿名函数是一个对象,所以它(包括lambda表达式)才可以被当成一个参数传递
  • 双冒号函数引用、匿名函数对象、lambda这三者本质都是函数类型的对象
  • Java8 中虽然也支持 lambda 方式的写法(SAM 转换),但是 Java8 中的 lambda 和 kotlin 中的 lambda 有本质的区别,一个是编译器的简化写法,一个是函数对象的传递。Java 中即便能写成 lambda 的方式,它也是生成的一个接口类的匿名对象。

在这里插入图片描述

  • kotlin 中的 const 用来声明编译时常量,作用同 java 里的 static final ,会用字面量直接替换调用处的变量。但它只能写在顶级作用域。

在这里插入图片描述
在这里插入图片描述

  • kotlin中函数对象作为参数传递以后,会创建一个临时对象给真正的函数调用
  • 这种函数如果是在for循环这样的高频调用的场景里,就会因为创建大量的临时对象而导致内存抖动和频繁的GC, 甚至引发OOM

在这里插入图片描述

  • 如果给函数加上inline关键字,它会将调用的函数插入到调用处进行平铺展开,这样就可以避免生成临时函数对象带来的影响。所以inline关键字的优化,要是针对高阶函数的。

inline、nolinline、crossinline

  • inline通过内联(即函数内容直插到调用处)的方式来编译函数
  • noinline局部关掉这个优化,来摆脱「不能把函数类型的参数当对象使用」的限制
  • crossinline让内联函数里的函数类型的参数可以被间接调用,代价是不能在 Lambda 表达式里使用 return

noinlinecrossinline 主要是用来解决加上 inline 之后,可能导致的一些副作用或者附带伤害,进行补救的措施,至于什么时候需要使用它们,不需要记住规则,因为 Android Studio 会在需要的时候提示它。

什么是 SAM 转换

SAM 转换(Single Abstract Method),是针对只有一个方法的接口类的简化写法,例如:

// Single Abstract Method
public interface Listener {
    void onChanged();
}

public class MyView {
    private Listener mListener;
    
    public void setListener(Listener listener) {
        mListener = listener;
    }
}
MyView view = new MyView();
view.setListener(new Listener() {
	@Override
    public void onChanged() {

    }
});

如果你写成这种写法,编译器就会提示你可以将其转换成 lambda 表达式(jdk 1.8):

在这里插入图片描述

于是代码就可以简化成下面这样:

MyView view = new MyView();
view.setListener(() -> {
	// todo
});

当然如果是在 kotlin 中调用 java 的这种代码,还可以将小括号去掉,直接调用方法后面跟上 {} 变成更彻底的 lambda 写法。

MyView().setListener { 
 	// todo
}

泛型中的 out 与 in

在Kotlin中out代表协变in代表逆变,为了加深理解我们可以将Kotlin的协变看成Java的上界通配符,将逆变看成Java的下界通配符

// Kotlin 使用处协变
fun sumOfList(list: List<out Number>)
// Java 上界通配符
void sumOfList(List<? extends Number> list)
// Kotlin 使用处逆变
fun addNumbers(list: List<in Int>)
// Java 下界通配符
void addNumbers(List<? super Integer> list)

我们知道 Java 的上界通配符和下界通配符主要用于函数的入参和出参,它们俩一个只读,一个只写,而 kotlin 中将这两个分别命名为outin在含义上更加明确了。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总的来说,Kotlin 泛型更加简洁安全,但是和 Java 一样都是有类型擦除的,都属于编译时泛型。

另外,kotlin 可以直接使用 outin 在类上指定泛型的读写模式,但是 Java 不可以:

// 这个类,就是只能获取,不能修改了
// 声明的时候加入 一劳永逸了 <out T>
class Worker<out T> {

	// 能获取
	fun getData(): T? = null
	
	// 不能修改
	/* 
	 * fun setData(data: T) { }
	 * fun addData(data: T) { }
	 */
}
// 这个类,就是只能修改,不能获取
// 声明的时候加入 一劳永逸了 <in T>
class Student<in T> {
	/* fun a(list: Mutablelist<in T>) **/
	
	fun setData(data: T) {}
	
	fun addData(data: T) {}
	
	// 不能获取
	// fun getData() : T
}
// Java 不允许你在声明方向的时候,控制读写模式
public class Student /*<? super T>*/ { 

}

在这里插入图片描述

  1. 类上的泛型 T 前面的 outin 关键字作用于整个类范围所有使用该泛型的地方。
  2. Kotlin 为什么这样设计:它表示所有使用 T 的场景都是只用来输出,或者只用来输入的,那么为了避免我在每个使用的位置都给变量或者参数写上out这么麻烦,就干脆直接声明在了类上面。
  3. 什么时候该用 outin :这是一个设计问题,类的设计者需要考虑这个类的职责,是否是只用于生产或者只用于消费的。

在类上使用 outin 时赋值的区别:

  • 子类泛型对象可以赋值给父类泛型对象,用 out
  • 父类泛型对象可以赋值给子类泛型对象,用 in

在这里插入图片描述

// 子类泛型对象可以赋值给父类泛型对象,用 out
val production1: Producer<Food> = FoodStore() 
val production2: Producer<Food> = FastFoodStore() 
val production3: Producer<Food>= BurgerStore() 
// 父类泛型对象可以赋值给子类泛型对象,用 in
val consumer1: Consumer<Burger> = Everybody() 
val consumer2: Consumer<Burger> = ModernPeople() 
val consumer3: Consumer<Burger> = American() 

这赋值这一点上, 使用 outin 与 Java 的上界通配符和下界通配符是一样的行为。

Kotlin 泛型中的 * 相当于Java 泛型中的 ?

在这里插入图片描述

Java 和 Kotlin 中类的泛型参数有多继承的区别:

在这里插入图片描述

Kotlin 泛型方法示例:

fun <T> instanceRetrofit(apiInterface: Class<T>) : T {
    // OKHttpClient 用于请求服务器
    val mOkHttpClient = OkHttpClient().newBuilder() 
        .readTimeout(10000, TimeUnit.SECONDS) // 添加读取超时时间 
        .connectTimeout(10000, TimeUnit.SECONDS) // 添加连接超时时间 
        .writeTimeout(10000, TimeUnit.SECONDS) // 添加写出超时时间
        .build()

    val retrofit: Retrofit = Retrofit.Builder()
        .client(mOkHttpClient) // 请求方,处理响应方
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 使用 RxJava 处理响应
        .addConverterFactory(GsonConverterFactory.create()) // 使用 Gson 解析 JavaBean
        .build()

    return retrofit.create(apiInterface)
}

简单总结一下:

kotlin的 out in 和 Java 的<? extends T><? super T> 虽然含义是一样的,但是写法上有点不同:

  • Java 的上界通配符和下界通配符只能用作方法的参数,用于入参和出参的作用,不能直接写到类上面。
  • kotlin 中的 out in 可以直接写到类上面,直接表明整个类中使用到泛型 T 的地方都具备这个含义。
  • 当在类上面声明泛型 Tout 时,表示 T 只能从当前类中输出,而不能输入。
  • 当在类上面声明泛型 Tin 时,表示 T 只能从当前类中输入,而不能输出。

Kotlin 标准库中的常用扩展函数 apply、also、run、let

使用时可以通过简单的规则作出一些判断:

  • 需要返回自身 -> 从 applyalso 中选
    • 作用域中使用 this 作为参数 ----> 选择 apply
    • 作用域中使用 it 作为参数 ----> 选择 also
  • 不需要返回自身 -> 从 runlet 中选择
    • 作用域中使用 this 作为参数 ----> 选择 run
    • 作用域中使用 it 作为参数 ----> 选择 let
  • apply 适合对一个对象做附加操作的时候
  • let 适合配合判空的时候 (最好是成员变量,而不是局部变量,局部变量更适合用 if )
  • with 适合对同一个对象进行多次操作的时候

apply VS also

applyalso 的返回值都是当前调用者的对象,也就是 T 类型的当前实例:

public inline fun <T> T.apply(block: T.() -> Unit): T { 
	block()
	return this 
}
public inline fun <T> T.also(block: (T) -> Unit): T { 
	block(this)
	return this 
}

这俩同是当前调用者 T 类型的扩展函数,但是 apply 中的 block 同时也是当前调用者 T 类型的扩展函数,所以其 lambda 中可以使用 this 访问当前对象,而 also 中的 block 只是一个普通的函数,不过这个普通函数的参数传入的是当前对象,所以其 lambda 中只能用 it 访问当前对象。

在这里插入图片描述

apply 常用于创建对象实例后,马上对其进行一些操作调用:

ArrayList<String>().apply { 
	add( "testApply")
	add("testApply") 
	add( "testApply") 
	println("$this") 
}.also { 
	println(it)
} 

let VS run

letrun 的返回值都是 block 的返回值,即 lambda 表达式的返回值:

public inline fun <T, R> T.let(block: (T) -> R): R { 
	return block(this)
}
public inline fun <T, R> T.run(block: T.() -> R): R { 
	return block()
} 

这俩同是当前调用者 T 类型的扩展函数,但是 run 中的 block 同时也是当前调用者 T 类型的扩展函数,所以其 lambda 中可以使用 this 访问当前对象,而 let 中的 block 只是一个普通的函数,不过这个普通函数的参数传入的是当前对象,所以其 lambda 中只能用 it 访问当前的对象。

在这里插入图片描述

let 比较常用的一个操作是判空操作

// 避免为 nu1ll 的操作
str?.let {
	println(it.length) 
}

object 单例

我们知道 object 就是 kotlin 中天生的单例模式,我们看一下它翻译成 Java 代码是什么样的:

object Singleton {
    var x: Int = 2 
    fun y() { }
}

上面代码编译成Java字节码后反编译对应如下代码:

在这里插入图片描述

其实它就是恶汉模式的单例

如果是一个普通类想生成单例,可以使用伴生对象 companion object 来生成:

class Singleton {
    companion object {
        var x: Int = 2
        fun y() { }
    }
}

上面代码翻译成 Java 后长下面这样:

在这里插入图片描述

我们看到它还是一个恶汉模式的单例,只不过这个恶汉的对象实例是一个名为 Companion静态内部类的实例对象。另外,只有 companion object 中的成员属性是放到外部类中的,而 companion object 中的成员方法是放在静态内部类中的。

如果要实现 Java 中静态内部类版本的单例模式

public class Singleton {

    private Singleton() {}
     
    private static class SingletonHolder {
        /** 静态初始化器,由 JVM 类加载过程来保证线程安全 */
        private static Singleton instance = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }
}

可以像下面这样写:

class Singleton private constructor() {

    private object Holder {
        val INSTANCE = Singleton()
    }
    
    companion object {
        val instance = Holder.INSTANCE
    }
}

Kotlin 中很没用的两个东西 Nothing 与 Unit

之所以说这两个东西没啥用,是因为这两个相当于是用来进行标记、提示之类的作用;只能说它们的实际用处不是那么大,但是用来标记和提醒比较方便。

比如在 Java 中,各种源码中可以看到类似下面的写法:

/**
* 当遇到姓名为空的时候,请调用这个函数来抛异常
* @return throw NullPointerException
*/
public String throwOnNameNull() {
   throw new NullPointerException("姓名不能为空!");
}

对应到 Kotlin 的等价写法:

/**
 * 当遇到姓名为空的时候,请调用这个函数来抛异常
 */
fun throwOnNameNull() : String {
    throw NullPointerException("姓名不能为空!")
}

这个函数的主要作用是用来抛出一个异常,但是如果这么写会让人很困惑,明明只是抛出异常,返回值却是一个String,所以这个时候可以用 Unit 或者 Nothing 代替它:

/**
 * 当遇到姓名为空的时候,请调用这个函数来抛异常
 */
fun throwOnNameNull() : Nothing {
    throw NullPointerException("姓名不能为空!")
}

这样开发者在看到这个函数时,就会知道,它什么也不会返回。就是一个提醒的作用。

Nothing 还可以用作泛型实参,以起到一个空白占位符的作用,例如:

val emptyList: List<Nothing> = listOf() 
var apples: List<Apple> = emptyList 
var users: List<User> = emptyList 
var phones: List<Phone> = emptyList 
var images: List<Image> = emptyList  

val emptySet: Set<Nothing> = setOf() 
var apples: Set<Apple> = emptySet 
var users: Set<User> = emptySet 
var phones: Set<Phone> = emptySet
var images: Set<Image> = emptySet  

val emptyMap: Map<String, Nothing> = emptyMap() 
var apples: Map<String, Apple> = emptyMap 
var users: Map<String, User> = emptyMap 
var phones: Map<String, Phone> = emptyMap 
var images: Map<String, Image> = emptyMap 
val emptyProducer: Producer<Nothing> = Producer() 
var appleProducer: Producer<Apple> = emptyProducer 
var userProducer: Producer<User> = emptyProducer 
var phoneProducer: Producer<Phone> = emptyProducer 
var imageProducer: Producer<Image> = emptyProducer 

这样写唯一的好处就是,简单方便,节省内存。

Nothing 还有一个作用就是当你不知道返回什么的时候,就可以返回它,例如:

fun sayMyName(first: String, second: String) {
	val name = if (first == "Walter" && second == "White") { 
		"Heisenberg"
	} else {
		return // 语法层面的返回值类型为 Nothing,赋值给 name 
	}
	println(name) 
}

这里虽然没有显示的写出来,但是在语法层面这里的 return 返回的就是 Nothing

对于 Unit,它主要用来对标 Java 中的 void 关键字,表示什么也不返回,即返回空。为什么要设计一个这个呢,直接使用 void 不就行了吗?这是因为 Java 中的 void 关键字,虽然表示返回空,但是它不是一个实际的类型,在某些地方,你就不能用它来作为一个类型去表达“什么也不返回”的含义,例如最常见的例子就是以前开发中经常使用的 AsyncTask

class BackgroundTask extends AsyncTask<String, Void, Void> {

 	@Override
    protected Void doInBackground(String... strings) {
        // do something
        return null;
    }

    @Override
    protected void onProgressUpdate(Void[] values) {
        super.onProgressUpdate(values);
    }

    @Override
    protected void onPostExecute(Void o) {

    }
}

回忆一下AsyncTask的三个泛型参数:public abstract class AsyncTask<Params, Progress, Result>

  • ParamsdoInBackground方法的接受参数类型
  • ProgressonProgressUpdate方法的接受参数类型
  • ResultonPostExecute方法的接受参数类型,以及doInBackground方法的返回参数类型

在上面代码中,由于void是一个关键字,而不是一个类型,所以不能用于泛型的位置作为实参,所以就会出现很尴尬的场景,我们必须再造一个类似于void关键字的类型,也就是大写的 Void(它其实是一个类),并且上面代码中,我们看到 doInBackground 方法的返回参数类型是 Void,但实际上是 return 了一个 null,而且你不写这个 null 又不行编译不过。这就令人非常尴尬了。

为了避免这种令人尴尬的场景,kotlin 就干脆直接定义了一个 Unit 类型来代表这种 Void,它是一个实际的类型,你可以用它来定义变量,它也可以出现在任何需要类型的地方。

在这里插入图片描述
在这里插入图片描述

但是 Kotlin 中一般函数没有返回值时,我们可以省略写这个 Unit

Unit 更常见的身影是 lambda 表达式以及高阶函数的参数定义中,例如:

fun foo(block : (Int, String) -> Unit) : Unit {
    return block(123, "hello")
}
val sum : (Int, Int) -> Unit = { x, y -> x + y }
fun main() {
    val a = sum(1, 2)
}

确切的说,在 Kotlin 中它的主要用途是用来表达函数类型,因为如果只是一个关键字的话,而不是一个类型,那么你就无法把它在需要表达函数类型的地方写出来。

关于 Unit 另外一个比较常见的场景是在 Jetpack Compose 的副作用 API 中的使用,例如:

LaunchedEffect(Unit) {
	...
}

这种写法显得比较奇怪,但是看一眼 Unit 的源码就明白了:

/**
 * The type with only one value: the `Unit` object. This type corresponds to the `void` type in Java.
 */
public object Unit {
    override fun toString() = "kotlin.Unit"
}

我们发现它就是一个 object 单例,而 object 对应到 Java 中就是一个 final 类,因此 object 单例在运行时是不变的,它就是一个常量

所以LaunchedEffect(Unit)也可以写成LaunchedEffect(1)LaunchedEffect(2)LaunchedEffect("aaa")LaunchedEffect(true)都可以,只不过你想不到写啥的时候,直接写 Unit 会更方便。

接口代理 by

它跟代理模式差不多,但是有一点不同的 kotlin 的 by 更多的是将一个接口的实现委托给一个实现类对象。

比如 Android 中的 ContextWrapper 就是将对 Context 的操作全部都委托给了内部一个叫做 mBaseContext 成员对象去处理:

public class ContextWrapper extends Context {
	Context mBase;
	
	public ContextWrapper(Context base) { 
		mBase = base; 
	}
	
	@Override
	public AssetManager getAssets() {
		return mBase.getAssets(); 
	}
	
	@Override
	public Resources getResources() {
	 	return mBase.getResources(); 
	}
	
	@Override
	public PackageManager getPackageManager() {
		return mBase.getPackageManager(); 
	}
	
	@Override
	public ContentResolver getContentResolver() { 
		return mBase.getContentResolver(); 
	}
	...
}

再比如我想定制一个类型是 UserList 对象,实现按年龄排序之类的需求,可以这样写:

class UserList implements List<User> {
	List<User> userList;
	
	public UserList(List<User> userList) { 
		this.userList = userList; 
	} 
	
	public List<User> higherRiskUsers() { ...}
	
	public void sortWithAge() { ...} 
	
	@Override
	public int size() { 
		return 0; 
	} 
	
	@Override
	public boolean isEmpty() { 
		return false;
	} 
	
	@Override
	public boolean contains(@Nullable Object o) { 
		return false;
	}
	......
} 

这样就是将对 List的操作委托给了内部的userList去操作,你可以传入一个ArrayList或者一个LinkedList的实现给它。

但是这样写的话,我们发现里面多了很多不需要但是不得不写的方法,例如size()isEmpty()等等,如果使用 Kotlin 的 by 关键字进行委托,就会简化很多,例如:

class UserList(private val list: List<User>): List<User> by list {
	
	public List<User> higherRiskUsers() { ...}
	
	public void sortWithAge() { ...} 	
}

这样那些不得不写但又没有营养的方法,我们就可以不用手动去写了,而是交给构造函数中传入的 list 参数的实现类实例对象去自动实现这些方法。我们只需要关心在这个类中,如何实现真正需要添加的业务方法即可。

总结一下它的语法就是:

class 类名(val 实际接口的实现者[a] : 接口类) : 接口类 by [a] {

}

其中 a 传入的就是要实现的接口的实际实现对象实例。

当然在使用 by 关键字也可以不完全委托给构造函数传入的实例对象,如果在类中覆写了所实现接口的某个方法,就会以你覆写的为准,而不是交给委托的对象,这一点比较灵活。

比如 Kotlin 的协程源码中有一个叫 SubscribedSharedFlow 就是对 SharedFlow 进行了委托,但是它没有完全委托给构造函数传入的sharedFlow对象,而是重写了SharedFlow接口的 collect 方法:

在这里插入图片描述
在这里插入图片描述

通过这种 方式我们可以进行某种“局部定制”功能,这个感觉有点类似 Java 里面你继承一个父类抽象类,但是懒于实现其每个抽象方法,但是又想在需要的时候自由覆盖其某个抽象方法,kotlin一个by关键字解决了这个麻烦。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1319685.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

社交网络分析4(上):社交网络链路预测分析、Logistic回归模型、LLSLP方法(LightGBM 堆叠链路预测)、正则化方法、多重共线性

社交网络分析4 写在最前面社交网络链路预测分析概述链路预测分析简介链路预测分析的重要性社交网络链路预测分析方法基于网络结构的方法基于节点属性的方法基于随机游走的方法基于深度学习的方法 基于相似性和基于似然性的链路预测方法基于相似性的方法基于邻居的方法基于路径的…

【工具使用-有道云笔记】如何在有道云笔记中插入目录

一&#xff0c;简介 本文主要介绍如何在有道云笔记中插入目录&#xff0c;方便后续笔记的查看&#xff0c;供参考。 二&#xff0c;具体步骤 分为两个步骤&#xff1a;1&#xff0c;设置标题格式&#xff1b;2&#xff0c;插入标题。非常简单~ 2.1 设置标题格式 鼠标停在标…

【深度学习目标检测】八、基于yolov5的抽烟识别(python,深度学习)

YOLOv5是目标检测领域一种非常优秀的模型&#xff0c;其具有以下几个优势&#xff1a; 1. 高精度&#xff1a;YOLOv5相比于其前身YOLOv4&#xff0c;在目标检测精度上有了显著的提升。YOLOv5使用了一系列的改进&#xff0c;如更深的网络结构、更多的特征层和更高分辨率的输入图…

硬件基础-电阻

电阻 1.品牌 厚声、风华&#xff0c;三星、罗姆、松下、KOA 2.分类 插件 碳膜电阻&#xff1a;精度-5 J 是在高阻&#xff0c;高压和高温应用中 属负温度系数电阻 金属膜&#xff1a;-1 F 贴片 电阻标识&#xff1a;&#xff08;含义&#xff1a;阻值大小和精度&a…

使用DETR 训练VOC数据集和自己的数据集

一、数据准备 DETR用的是COCO格式的数据集。 如果要用DETR训练自己的数据集&#xff0c;直接利用Labelimg标注成COCO格式。如果是VOC数据集的话&#xff0c;要做一个格式转换&#xff0c;yolo格式的数据集&#xff0c;转换成coco格式 COCO数据集的格式类似这样&#xff0c;a…

【改进YOLOv8】磁瓦缺陷分类系统:改进LSKNet骨干网络的YOLOv8

1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 研究背景与意义 近年来&#xff0c;随着智能制造产业的不断发展&#xff0c;基于人工智能与机器视觉的自动化产品缺陷检测技术在各行各业中得到了广泛应用。磁瓦作为永磁电机的主…

verilog基础语法-计数器

概述&#xff1a; 计数器是FPGA开发中最常用的电路&#xff0c;列如通讯中记录时钟个数&#xff0c;跑马灯中时间记录&#xff0c;存储器中地址的控制等等。本节给出向上计数器&#xff0c;上下计数器以及双向计数器案例。 内容 1. 向上计数器 2.向下计数器 3.向上向下计数…

迷你型洗衣机好用吗?高性价比的四款内衣洗衣机推荐

不得不说内衣洗衣机的发明解放了我们的双手&#xff0c;而我们从小到大就有这个意识&#xff0c;贴身衣物不可以和普通的衣服一起丢进去洗衣机一起&#xff0c;而内衣裤上不仅有肉眼看见的污渍还有手上根本无法消灭的细菌&#xff0c;但是有一款专门可以将衣物上的细菌杀除的内…

机器学习——自领域适应作业

任务 游戏里面的话有很多跟现实不一样的情况。 想办法让中间的特征更加的接近&#xff0c;让feat A适应feat B&#xff0c;产生相对正常的输出。 在有标签数据和没有数据的上面进行训练&#xff0c;并能预测绘画图像。 数据集 训练5000张总数&#xff0c;每类有500张测试100…

人工智能数据挖掘:发掘信息的新境界

导言 人工智能数据挖掘作为信息时代的利器&#xff0c;通过智能算法和大数据技术的结合&#xff0c;为企业、学术研究和社会决策提供了前所未有的洞察力。本文将深入探讨人工智能在数据挖掘领域的应用、技术挑战以及对未来的影响。 1. 人工智能数据挖掘的基本原理 数…

Python学习笔记(一)Anaconda开发环境介绍与搭建

本文介绍了Python学习中常用的开发环境Anaconda&#xff0c;以及如何搭建和使用Anaconda。Anaconda是一个集成了许多模块和包管理工具的软件集合&#xff0c;可以管理Python解释器、模块和虚拟环境。文章还比较了conda和pip这两个包管理工具的区别&#xff0c;并介绍了Anaconda…

Unity实现GoF23种设计模式

文章目录 Unity实现GoF23种设计模式概要一、创建型模式(Creational Patterns):二、结构型模式(Structural Patterns):三、行为型模式(Behavioral Patterns):Unity实现GoF23种设计模式概要 GoF所提出的23种设计模式主要基于以下面向对象设计原则: 对接口编程而不是对实…

Lambda表达式的简单理解

1. 初识lambda表达式 Lambda表达式是Java SE 8中一个重要的新特性。lambda表达式允许你通过表达式来代替功能接口。 lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。 Lambda 表达式&#xff08;Lambda exp…

✺ch4——管理3D图形数据

目录 缓冲区和顶点属性统一变量顶点属性插值应用变换矩阵一个3D立方体示例渲染一个对象的多个副本——实例化在同一场景中渲染多个不同模型矩阵栈应对“Z冲突”伪影图元的其他选项性能优先的编程方法 使用 OpenGL 渲染 3D 图形通常需要将若干数据集发送给 OpenGL 着色器管线。举…

DS哈希查找—线性探测再散列

Description 定义哈希函数为H(key) key%11&#xff0c;输入表长&#xff08;大于、等于11&#xff09;。输入关键字集合&#xff0c;用线性探测再散列构建哈希表&#xff0c;并查找给定关键字。 –程序要求– 若使用C只能include一个头文件iostream&#xff1b;若使用C语言…

giee 添加公匙 流程记录

一、安装 百度网盘CSDN4文件夹下&#xff0c;或者官网下载&#xff1a;https://git-scm.com/downloads 二、生成密钥 1.右击打开git bash 2.$ ssh-keygen -t rsa -C “个人邮箱地址”&#xff0c;按3个回车&#xff0c;密码为空。 3.在C:\Users{windows用户名}.ssh目录下得到…

玩转字词句魔法:打造超强样本集的数据增强策略,句式变换揭秘同义句生成与回译在数据增强中的创新应用

NLP专栏简介&#xff1a;数据增强、智能标注、意图识别算法|多分类算法、文本信息抽取、多模态信息抽取、可解释性分析、性能调优、模型压缩算法等 专栏详细介绍&#xff1a;NLP专栏简介&#xff1a;数据增强、智能标注、意图识别算法|多分类算法、文本信息抽取、多模态信息抽取…

【PHP】一个邮箱点击验证的完整示例

目录 1.效果展示 2.发送验证码 3.进行验证 以绑定邮箱为例&#xff0c;注册验证的话修改判断逻辑 1.效果展示 2.发送验证码 /*** 发点击验证* 参数 email*/public function sendClick(){$param $this->request->post();// 邮箱email的validate规则验证&#xff0c;略…

酒精壁炉,现代取暖的便携选择

酒精壁炉作为现代室内取暖的一种选择&#xff0c;具有独特的特点和工作原理。酒精壁炉采用酒精作为燃料&#xff0c;为家庭提供舒适的温暖&#xff0c;同时具备一定的安全性和便携性。 酒精壁炉通常由金属或陶瓷制成&#xff0c;内部设有专门的燃烧器&#xff0c;用于燃烧酒精燃…

SpringBoot使用@DS配置 多数据源 【mybatisplus druid datasource mysql】

项目最近需要使用多数据源&#xff0c;不同的mapper分别读取不同的链接&#xff0c;本项目使用了mybatisplus druid 来配置多数据源&#xff0c;基于mysql数据库。 目录 1.引入依赖 ​2.配置文件 application.yaml 3.Mapper中使用DS切换数据源 4.使用DS的注意事项 1.引入依…