Kotlin基础(六) 枚举类和扩展

news2024/11/25 2:24:27

前言

本文主要讲解kotlin枚举类和扩展


Kotlin文章列表

Kotlin文章列表: 点击此处跳转查看


目录

在这里插入图片描述


1.1 枚举类

1.1.1 枚举类的基本用法

Kotlin中的枚举类(enum class)用于定义一组具有预定义值的常量。它们在许多情况下都很有用,例如表示一组相关的选项、状态或命名常量集合。下面是Kotlin枚举类的基本用法:

  1. 声明枚举类:

    enum class Direction {
        NORTH, SOUTH, EAST, WEST
    }
    
  2. 使用枚举值:

    val direction = Direction.NORTH
    println(direction)  // 输出: NORTH
    
  3. 比较枚举值:

    val direction = Direction.NORTH
    if (direction == Direction.NORTH) {
        println("向北")
    }
    
  4. 遍历枚举值:

    for (enumValue in Direction.values()) {
        println(enumValue)
    }
    
  5. 获取枚举值的名称:

    val direction = Direction.NORTH
    println(direction.name)  // 输出: NORTH
    
  6. 获取枚举值的序号(从0开始):

    val direction = Direction.NORTH
    println(direction.ordinal)  // 输出: 0
    
  7. 使用枚举类的方法和属性:

    enum class Direction {
        NORTH {
            override fun printDescription() {
                println("这是北方")
            }
        },
        SOUTH {
            override fun printDescription() {
                println("这是南方")
            }
        },
        EAST {
            override fun printDescription() {
                println("这是东方")
            }
        },
        WEST {
            override fun printDescription() {
                println("这是西方")
            }
        };
    
        abstract fun printDescription()
    }
    
    val direction = Direction.NORTH
    direction.printDescription()  // 输出: 这是北方
    

这些是Kotlin枚举类的基本用法。

1.1.2 为枚举值指定对应的数值

在Kotlin中,你可以为枚举值指定对应的数值。默认情况下,每个枚举值会自动分配一个从0开始递增的整数值作为其数值。然而,你也可以显式地为枚举值指定自定义的数值。下面是为枚举值指定数值的几种方式:

  1. 基本数值分配:

    enum class Direction {
        NORTH, SOUTH, EAST, WEST
    }
    

    在这种情况下,NORTH的数值为0,SOUTH的数值为1,以此类推。

  2. 自定义数值分配:

    enum class Direction(val degrees: Int) {
        NORTH(0), SOUTH(180), EAST(90), WEST(270)
    }
    

    在这个例子中,每个枚举值都有一个degrees属性来存储对应的数值。NORTH的数值为0,SOUTH的数值为180,以此类推。

  3. 使用匿名类和属性来分配数值:

    enum class Direction {
        NORTH {
            override val degrees: Int = 0
        },
        SOUTH {
            override val degrees: Int = 180
        },
        EAST {
            override val degrees: Int = 90
        },
        WEST {
            override val degrees: Int = 270
        };
    
        abstract val degrees: Int
    }
    

    在这个例子中,每个枚举值都通过匿名类来定义,并重写了degrees属性以指定数值。

你可以根据需要选择适合的方式来为枚举值指定数值。这样,你就可以在需要使用枚举值数值的地方访问这些数值。例如,对于第二个示例中的Direction枚举类,你可以通过direction.degrees来访问特定枚举值的数值。

1.1.3 枚举类的其他功能

除了基本用法外,Kotlin枚举类还提供了其他一些功能,使其更加灵活和强大。以下是一些Kotlin枚举类的其他功能:

  1. 声明方法:
    枚举类可以声明方法,可以在每个枚举值上调用这些方法。例如:

    enum class Direction {
        NORTH {
            override fun getOpposite(): Direction = SOUTH
        },
        SOUTH {
            override fun getOpposite(): Direction = NORTH
        },
        EAST {
            override fun getOpposite(): Direction = WEST
        },
        WEST {
            override fun getOpposite(): Direction = EAST
        };
    
        abstract fun getOpposite(): Direction
    }
    
    

    每个枚举值都实现了getOpposite()方法,根据当前方向返回相反的方向。

  2. 实现接口:
    枚举类可以实现接口。这使得你可以为枚举类的每个枚举值提供不同的实现。例如:

    interface Printable {
        fun print()
    }
    
    enum class Direction : Printable {
        NORTH {
            override fun print() {
                println("北方")
            }
        },
        SOUTH {
            override fun print() {
                println("南方")
            }
        },
        EAST {
            override fun print() {
                println("东方")
            }
        },
        WEST {
            override fun print() {
                println("西方")
            }
        };
    }
    
    

    在这个例子中,Direction枚举类实现了Printable接口,并为每个枚举值提供了不同的print()方法实现。

  3. 通过字符串获取枚举值:
    你可以通过枚举值的字符串名称来获取对应的枚举值。使用valueOf()函数实现这一点。例如:

    val direction = Direction.valueOf("NORTH")
    println(direction)  // 输出: NORTH
    

    这将返回枚举值NORTH

  4. 定义扩展函数和属性:
    你可以为枚举类定义扩展函数和属性,为枚举值添加额外的功能。例如:

    enum class Direction {
        NORTH, SOUTH, EAST, WEST
    }
    
    fun Direction.isVertical(): Boolean {
        return this == Direction.NORTH || this == Direction.SOUTH
    }
    
    val Direction.opposite: Direction
        get() = when (this) {
            Direction.NORTH -> Direction.SOUTH
            Direction.SOUTH -> Direction.NORTH
            Direction.EAST -> Direction.WEST
            Direction.WEST -> Direction.EAST
        }
    

    在这个例子中,isVertical()是一个扩展函数,用于判断枚举值是否为垂直方向。opposite是一个扩展属性,根据当前方向返回相反的方向。

这些是Kotlin枚举类的一些其他功能,它们使得枚举类更加灵活和可扩展。

1.2 扩展

1.2.1 扩展原生API

Kotlin提供了扩展函数和扩展属性的功能,使你能够扩展原生的API类,包括标准库和其他类库中的类。这使你能够在不修改原始类代码的情况下为这些类添加新的功能。下面是如何在Kotlin中扩展原生API的几种方法:

  1. 扩展函数:
    你可以为任何类定义扩展函数。要定义一个扩展函数,你需要在函数名前面加上接收者类型并使用点符号。例如,以下是为字符串类型扩展一个reverse()函数:

    fun String.reverse(): String {
        return this.reversed()
    }
    
    

    使用示例:

    val reversedString = "Hello, World!".reverse()
    println(reversedString)  // 输出: "!dlroW ,olleH"
    
    

    在这个例子中,我们扩展了String类,添加了一个reverse()函数,以反转字符串的顺序。

  2. 扩展属性:
    与扩展函数类似,你还可以为类定义扩展属性。要定义一个扩展属性,你可以使用get()和(可选)set()函数。以下是为Int类型扩展一个isEven属性:

    val Int.isEven: Boolean
        get() = this % 2 == 0
    
    

    使用示例:

    val number = 6
    println(number.isEven)  // 输出: true
    
    

    在这个例子中,我们扩展了Int类,添加了一个isEven属性,用于判断一个整数是否为偶数。

  3. 扩展标准库:
    Kotlin的标准库提供了许多常见类型的扩展函数和属性,使你能够以更简洁的方式处理数据。例如,标准库中的List类提供了许多方便的扩展函数,如filter()map()reduce()等,用于对列表进行操作和转换。

    val numbers = listOf(1, 2, 3, 4, 5)
    val evenNumbers = numbers.filter { it % 2 == 0 }
    val doubledNumbers = numbers.map { it * 2 }
    val sum = numbers.reduce { acc, value -> acc + value }
    
    

    在这个例子中,我们使用了filter()函数筛选出偶数,使用map()函数将每个数字乘以2,使用reduce()函数计算数字的总和。

扩展原生API使你能够根据自己的需求为现有类添加新的功能,提高代码的可读性和可维护性。请注意,扩展函数和属性仅在调用它们的作用域内可见,并且它们不能访问类的私有或受保护成员。

1.2.2 扩展自定义类

在Kotlin中,你不仅可以扩展原生的API类,还可以扩展自定义的类。这使你能够为自己的类添加新的功能或方法,以满足特定的需求。下面是如何在Kotlin中扩展自定义类的几种方法:

  1. 扩展函数:
    你可以为自定义的类定义扩展函数,以添加新的功能。要定义一个扩展函数,你需要在函数名前面加上接收者类型并使用点符号。例如,假设你有一个名为Person的自定义类,你可以为它添加一个greet()函数:

    class Person(val name: String)
    
    fun Person.greet() {
        println("Hello, $name!")
    }
    
    

    使用示例:

    val person = Person("John")
    person.greet()  // 输出: "Hello, John!"
    
    

    在这个例子中,我们为Person类添加了一个greet()函数,以便在实例上调用该函数时打印出问候语。

  2. 扩展属性:
    与扩展函数类似,你还可以为自定义的类定义扩展属性。要定义一个扩展属性,你可以使用get()和(可选)set()函数。以下是为Person类扩展一个age属性:

    class Person(val name: String)
    
    val Person.age: Int
        get() = 30
    
    

    使用示例:

    val person = Person("John")
    println(person.age)  // 输出: 30
    
    

    在这个例子中,我们为Person类添加了一个age属性,始终返回30。

  3. 扩展其他自定义类:
    你可以为任何自定义类定义扩展函数和属性,无论它们是你自己编写的类还是来自其他类库。只需按照相同的语法和规则创建扩展函数和属性即可。例如:

    class Rectangle(val width: Int, val height: Int)
    
    fun Rectangle.isSquare(): Boolean {
        return width == height
    }
    
    

    使用示例:

    val rectangle = Rectangle(5, 5)
    println(rectangle.isSquare())  // 输出: true
    

    在这个例子中,我们为Rectangle类添加了一个isSquare()函数,用于判断矩形是否为正方形。

扩展自定义类使你能够在不修改原始类代码的情况下为它们添加新的功能。这样可以提高代码的可读性、可维护性和灵活性。扩展函数和属性仅在调用它们的作用域内可见,并且它们不能访问类的私有或受保护成员。

1.2.3 成员函数冲突的解决方案

在Kotlin中,当你扩展的类和目标类具有相同名称的成员函数时,会发生函数冲突。这种情况下,编译器无法确定应该使用哪个函数。为了解决这个问题,你可以采取以下两种解决方案:

  1. 显式指定调用的函数:
    当发生函数冲突时,你可以使用类名作为限定符,显式指定调用哪个类的函数。例如,假设你有一个名为String的扩展函数toUpperCase(),但是String类本身也有一个toUpperCase()函数,你可以使用类名来调用扩展函数:

    fun String.toUpperCase(): String {
        return "Extension function"
    }
    
    fun main() {
        val str = "Hello"
        println(str.toUpperCase())         // 调用目标类的函数
        println(str.String.toUpperCase())  // 调用扩展函数
    }
    

    在这个例子中,我们通过使用类名String作为限定符,显式调用了扩展函数toUpperCase()和目标类的函数toUpperCase()

  2. 使用@JvmName注解:
    另一种解决函数冲突的方法是使用@JvmName注解为扩展函数指定一个不同的Java虚拟机名称。这样可以避免函数名称冲突。例如:

    @file:JvmName("StringUtil")
    
    package com.example.utils
    
    fun String.toUpperCase(): String {
        return "Extension function"
    }
    
    

    在这个例子中,我们使用@JvmName注解将扩展函数toUpperCase()的Java虚拟机名称设置为StringUtil.toUpperCase(),避免了与目标类的函数冲突。

    注意:@JvmName注解应该放在扩展函数所在的文件的顶部。

通过显式指定调用的函数或使用@JvmName注解,你可以解决函数冲突问题,并确保在扩展类和目标类具有相同名称的成员函数时,能够正确地调用所需的函数。

1.2.4 扩展属性

在Kotlin中,你可以通过扩展属性为类添加新的属性。扩展属性允许你为现有类添加新的属性,而无需修改其源代码。以下是如何在Kotlin中扩展属性的示例:

// 假设有一个名为Person的类
class Person(val name: String)

// 为Person类添加一个扩展属性age
val Person.age: Int
    get() = 30

fun main() {
    val person = Person("John")
    println(person.age)  // 输出: 30
}

在上述示例中,我们为Person类添加了一个扩展属性age。扩展属性的定义类似于扩展函数,但是在这种情况下,我们只需要定义get()函数来获取属性的值。

请注意以下事项:

  • 扩展属性不能有初始值,因为它们没有与之关联的字段。因此,你需要提供一个get()函数来计算属性的值。
  • 扩展属性不支持set()函数,因此它们是只读的。

与扩展函数一样,扩展属性仅在调用它们的作用域内可见,并且它们不能访问类的私有或受保护成员。

通过使用扩展属性,你可以方便地为现有类添加新的属性,从而提供更灵活的数据操作和访问方式。

1.2.5 扩展伴随对象(CompanionObject)

在Kotlin中,你可以使用扩展函数和扩展属性来扩展伴随对象(companion object)。伴随对象是与类关联的单例对象,它可以包含类级别的函数和属性。以下是如何扩展伴随对象的示例:

class MyClass {
    companion object {
        fun greet() {
            println("Hello from companion object!")
        }
    }
}

// 扩展伴随对象的函数
fun MyClass.Companion.sayHello() {
    println("Hello from extension function of companion object!")
}

fun main() {
    MyClass.greet()      // 调用伴随对象的函数
    MyClass.sayHello()   // 调用扩展函数
}

在上述示例中,我们有一个包含伴随对象的MyClass类。我们可以通过直接使用类名调用伴随对象的函数greet()

然后,我们使用扩展函数的语法来为伴随对象添加新的函数sayHello()。这样,我们可以使用伴随对象的函数和扩展函数来进行调用。

请注意以下事项:

  • 扩展伴随对象的函数或属性的定义需要使用Companion关键字作为限定符。
  • 扩展伴随对象的函数和属性可以与伴随对象内部定义的函数和属性共存,它们在调用时使用相同的语法。

通过扩展伴随对象,你可以为伴随对象添加新的功能,而无需修改原始类的源代码。这使得你可以更灵活地扩展伴随对象并为其添加额外的行为。

1.2.6 扩展的范围

在Kotlin中,扩展的范围(可见性)是受限的,扩展函数和属性只在特定的作用域内可见。以下是关于Kotlin扩展范围的几点要注意的事项:

  1. 扩展函数和属性的作用域:
    • 在顶层:你可以在文件的顶层定义扩展函数和属性,它们将在整个文件中可见。
    • 在类内部:你可以在类内部定义扩展函数和属性,它们将在类的范围内可见。
  2. 可见性限制:
    • 扩展函数和属性不能访问类的私有或受保护成员。它们只能访问类中的公共成员。
    • 扩展函数和属性不会继承给子类。只有在扩展函数或属性定义所在的作用域内才可见,无法通过继承传递给子类。
  3. 导入扩展:
    • 要使用扩展函数和属性,你需要在使用它们的文件中导入它们所在的包或文件。
    • 如果扩展函数或属性在同一个包内,你不需要导入,可以直接使用。
    • 如果扩展函数或属性在不同的包内,你需要使用import关键字导入它们。

例如,假设有以下代码:

package com.example.utils

fun String.reverse(): String {
    return this.reversed()
}

class MyClass {
    fun doSomething() {
        val str = "Hello"
        println(str.reverse())
    }
}

fun main() {
    val str = "World"
    println(str.reverse())
}

在这个例子中,reverse()扩展函数位于com.example.utils包中。在main()函数中,我们需要导入reverse()函数所在的包才能使用它。而在MyClass类的doSomething()函数中,由于在同一个包内,所以无需导入即可使用。

总结起来,扩展函数和属性的范围是局限于定义它们的作用域内。你需要正确导入扩展函数和属性所在的包或文件,才能在其他地方使用它们。另外,扩展函数和属性无法访问类的私有或受保护成员。

1.2.7 在类中使用扩展

在Kotlin中,你可以在类内部使用扩展函数和扩展属性。这样做可以为类添加额外的功能,而无需修改类的源代码。以下是如何在类中使用扩展的示例:

class MyClass {
    private val data: MutableList<String> = mutableListOf()

    fun addData(item: String) {
        data.add(item)
    }

    fun displayData() {
        println("Data: $data")
    }

    // 在类内部定义扩展函数
    fun MyClass.processData() {
        data.forEach {
            println("Processing: $it")
        }
    }

    // 在类内部定义扩展属性
    val MyClass.totalDataSize: Int
        get() = data.size
}

fun main() {
    val myObj = MyClass()
    myObj.addData("Item 1")
    myObj.addData("Item 2")
    myObj.addData("Item 3")

    myObj.displayData()              // 输出: Data: [Item 1, Item 2, Item 3]
    myObj.processData()              // 输出: Processing: Item 1, Processing: Item 2, Processing: Item 3
    println(myObj.totalDataSize)     // 输出: 3
}

在上述示例中,我们在MyClass类内部定义了一个扩展函数processData()和一个扩展属性totalDataSize。这些扩展函数和属性可以直接在类的实例上使用。

请注意以下事项:

  • 在类内部定义的扩展函数和属性可以直接访问类的私有成员。
  • 在类内部定义的扩展函数和属性只在类的实例上可见,不能在类的伴随对象或其他作用域中访问。

通过在类内部使用扩展函数和属性,你可以为类添加特定的功能,与类的其他成员一起工作,并直接在类的实例上使用它们。这样可以提高代码的可读性和可维护性,并使类的功能更加灵活。

1.2.8 调用特定类的成员函数

在Kotlin中,你可以使用限定符(qualifier)来调用特定类的成员函数。通过限定符,你可以明确指定调用哪个类的成员函数,尤其在存在函数名称冲突或多个类具有相同函数名时很有用。以下是几种使用限定符调用特定类成员函数的方法:

  1. 使用类名作为限定符:

    class MyClass {
        fun myFunction() {
            println("Hello from MyClass")
        }
    }
    
    fun main() {
        val obj = MyClass()
        obj.myFunction()     // 调用MyClass的myFunction函数
    }
    

    在这个例子中,我们通过创建MyClass的实例obj来调用它的成员函数myFunction()。通过实例对象限定符,我们明确地指定了调用的是MyClass的成员函数。

  2. 使用扩展函数:

    class MyClass {
        fun myFunction() {
            println("Hello from MyClass")
        }
    }
    
    fun MyClass.anotherFunction() {
        println("Hello from extension function")
    }
    
    fun main() {
        val obj = MyClass()
        obj.myFunction()         // 调用MyClass的myFunction函数
        obj.anotherFunction()    // 调用MyClass的扩展函数
    }
    

    在这个例子中,我们在MyClass类外部定义了一个扩展函数anotherFunction()。通过在实例对象上调用该扩展函数,我们仍然是明确指定了要调用的是MyClass的函数。

使用限定符的好处是可以避免函数名称冲突,并确保在存在多个类具有相同函数名的情况下,调用的是正确的类的函数。

需要注意的是,限定符只能用于调用类的成员函数,无法用于调用类的扩展函数。扩展函数的调用需要使用扩展函数的定义作用域来限定,而不是使用限定符。

1.2.9 扩展成员的继承

在Kotlin中,扩展函数和属性是静态解析的,它们不会被子类继承。这意味着在子类中定义相同名称的函数或属性不会覆盖或继承父类的扩展函数或属性。相反,子类会拥有自己独立的同名成员函数或属性。

让我们看一个示例来说明这一点:

open class Parent

fun Parent.printMessage() {
    println("Hello from Parent")
}

class Child : Parent()

fun Child.printMessage() {
    println("Hello from Child")
}

fun main() {
    val parent: Parent = Child()
    parent.printMessage()  // 输出: Hello from Parent
}

在这个例子中,我们有一个Parent类和一个Child类,Child类继承自Parent类。我们在Parent类中定义了一个扩展函数printMessage(),然后在Child类中定义了一个同名的函数。

当我们通过Child类的实例来调用printMessage()函数时,实际上调用的是Parent类的扩展函数。这是因为扩展函数是静态解析的,它们的调用在编译时就确定了,而不是在运行时根据实际对象的类型进行动态分派。

因此,子类无法继承或覆盖父类的扩展函数或属性。扩展函数和属性仅在定义它们的作用域内可见,并且它们不能通过继承传递给子类。

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

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

相关文章

介绍性能压力测试的重要性

在当今数字化时代&#xff0c;软件和应用程序的性能对于用户体验和业务成功至关重要。为了确保系统在面临高负载和压力时能够正常运行&#xff0c;性能压力测试成为一项不可或缺的活动。本文将介绍性能压力测试的重要性。 性能压力测试是一种通过模拟实际场景中的负荷和用户访问…

Echarts中饼状图,图例显示value而不是name

直接上代码 formatter(name) {var tarValue;for (var i 0; i < data.length; i) {if (data[i].name name) {tarValue data[i].value;}}var v tarValue;return [tarValue]} 效果图

spring boot 多模块项目搭建Knife4j文档,swagger-ui x2

介绍: knife4j jeecg-boot用的就是这个&#xff0c;我之前要搭过swagger-ui&#xff0c;但外观&#xff0c;体验都没有knife4j好&#xff0c;我没记错的话已经停止发布版本了&#xff0c;所以我的多模块项目就用到了这个&#xff0c;还搭建了jwt token获取我也是在网上找的…

260道2023最新网络安全工程师面试题(附答案)

2023年过去了一大半&#xff0c;先来灵魂三连问&#xff0c;年初定的目标完成多少了&#xff1f;薪资涨了吗&#xff1f;女朋友找到了吗&#xff1f; ​好了&#xff0c;不扎大家的心了&#xff0c;接下来进入正文。 由于我之前写了不少网络安全技术相关的文章和回答&#xff…

pdf文件如何生成长图?分享两个免费的方法给大家!

在某些情况下&#xff0c;我们可能需要将长图转换为PDF文件&#xff0c;以便更方便地分享和存档。本文将介绍两种免费的方法&#xff0c;帮助您实现这一目标。方法一是使用记灵在线工具的PDF转长图功能&#xff0c;方法二是利用PDF24工具进行转换。让我们一起来了解具体操作步骤…

blender 叶片制作

圆润叶片 效果展示 shift a 新建矩形&#xff0c;s y 延 y 轴方向压扁&#xff0c;ctrl r 循环切割&#xff0c;滚动滚轮&#xff0c;延 y 轴方向切两条循环线&#xff0c;框选点&#xff0c;s 缩放&#xff0c;调整到叶片造型&#xff0c;添加细分修改器&#xff1b;给叶片…

构建数据中台的三要素:方法论、组织和技术

知道要转型&#xff0c;要建设数据中台&#xff0c;却不知咋做&#xff0c;咋办&#xff1f; 现在有很多讲“如何建设数据中台”文章&#xff0c;观点各不相同&#xff1a; 数据中台是数据建设方法论&#xff0c;按照数据中台设计方法和规范实施就可建成数据中台数据中台背后…

WPF嵌入外部exe应用程序-去除子窗体边框样式

WPF嵌入外部exe应用程序-去除子窗体边框样式 去除子窗体边框样式导入winodows API使用API去除边框报错&#xff1a;解决实现效果 完整实现代码 接着上一篇WPF嵌入外部exe应用程序-实现基本的嵌入&#xff0c;解决子窗体边框样式问题,去掉子窗体样式&#xff0c;让其融为一体&am…

家政上门小程序|同城家政预约上门小程序开发|上门家政软件源码

随着生活水平的提高&#xff0c;越来越多的人开始借助家政服务来解决日常生活中的琐事。为了方便用户寻找和预约家政服务&#xff0c;家政上门小程序应运而生。家政上门小程序开发具有多种功能&#xff0c;使其成为家政服务行业的重要工具。本文将介绍一些家政上门小程序开发的…

品牌营销策略:如何有效打造品牌知名度与口碑?

品牌营销策略是企业在市场竞争中脱颖而出的重要手段&#xff0c;它能够帮助企业树立品牌形象&#xff0c;提升品牌知名度&#xff0c;增强品牌影响力&#xff0c;从而获得更多的市场份额和利润。那么&#xff0c;如何制定一套有效的品牌营销策略呢&#xff1f;以下是一秒推小编…

《向量数据库指南》:向量数据库Pinecone管理索引教程(一)

在本节中,我们将说明如何获取索引列表、创建索引、删除索引和描述索引。 要了解与索引相关的概念,请参见索引。 ⚠️警告 Starter(免费)计划上的索引将在7天的不活动后被删除。为了 防止这种情况,请发送任何API请求或登录控制台。这将计算为 活动。 获取有关您的索…

解决appium-doctor报 mjpeg-consumer cannot be found

解决appium-doctor报 mjpeg-consumer cannot be found npm i -g mjpeg-consumer

深入开箱跑分全志A523平板电脑 台电P26T

首先外观和观感就不说了&#xff0c;图都有&#xff0c;来看看内部实际的东西。 主控全志A523M00X0000&#xff0c;配套Android 13 5.15 Kernel系统。4G内存&#xff0c;64G eMMC&#xff0c;屏幕1280*800分辨率。 平板开启了安全启动所以想买来开发刷机可以歇歇了 &#xf…

C++基础项目实战之通讯录管理系统

赶时间的可以看改进版的通讯录管理系统 通讯录管理系统 文章目录 通讯录管理系统1. 系统需求2. 菜单功能3. 退出功能4. 添加联系人4.1 设计联系人结构体4.2 设计通讯录结构体 5. 显示联系人5.1 封装显示联系人函数 6. 删除联系人6.1 封装检测联系人是否存在6.2 封装删除联系人函…

再度合作|极智嘉(Geek+) P系列拣选机器人进驻CEVA欧洲物流中心

近日&#xff0c;3PL巨头CEVA Logistics首度在社交媒体展示其与极智嘉(Geek)合作打造的全新欧洲物流中心&#xff0c;并在推文中对极智嘉(Geek)给予了高度赞扬。CEVA表示&#xff0c;极智嘉不仅彻底颠覆了CEVA的工作环境&#xff0c;还充分保障了敬业员工的安全和人体工程学效率…

2.6 线性表的逆置

逆置: 将表中的元素调整成与原来相反的顺序. 1. 顺序表的逆置 图1. 顺序表的逆置 用temp存储要交换的元素, temp arr[ i ]; arr[ i ] arr[ j ]; arr[ j ] temp; 然后i, j--. 若数组长度为偶数, 则i > j时结束循环; 若数组长度为奇数, 则i > j时结束循环. 也即不管数…

ABAP W CVI_EI 047 对供应商,不支持初始的 OBJECT_TASK

调BAPI:cl_md_bp_maintain>maintain修改供应商失败&#xff0c;提示 W CVI_EI 047 对供应商&#xff0c;不支持初始的 OBJECT_TASK 很可能是vendor-header中的object_task没有赋值 ls_data-vendor-header-object_task ‘U’.

C进阶:指针的进阶(3)

函数指针 首先来看一段代码&#xff1a; #include <stdio.h>void test() {printf("hehe\n"); }int main() {printf("%p\n", test);printf("%p\n", &test);return 0; } 让我们来看一下执行结果吧&#xff1a; 从上述结果得出&#x…

OCR-字符识别笔记

安装 环境依赖 Linux | Windows | macOSPython 3.7PyTorch 1.6 或更高版本torchvision 0.7.0CUDA 10.1NCCL 2GCC 5.4.0 或更高版本准备环境 注解 如果你已经在本地安装了 PyTorch,请直接跳转到安装步骤。 第一步 下载并安装 Miniconda. 第二步 创建并激活一个 conda 环境…

[PCIE体系结构导读]PCI和PCI中断

PCI PCI总桥由HOST主桥和PCI桥推出&#xff0c;HOST主桥与主存储器控制器在同一级总线上&#xff0c;因此PCI设备可以方便地通过HOST主桥访问主存储器&#xff0c;即进行DMA操作。 PCI设备的DMA操作需要与处理器系统的Cache进行一致性操作&#xff0c;当PCI设备通过HOST主桥访…