仓颉编程语言:接口

仓颉编程语言详解:高效、安全、灵活的全场景开发利器【仓颉语言接口指南大全】 仓颉编程语言是一种面向全场景应用开发的通用编程语言,致力于兼顾开发效率和运行性能,同时提供良好的编程体验。语法简明高效:仓颉编程语言提供了一系列简明高效的语法,旨在减少冗余书写、提升开发效率。例如,插值字符串、主构造函数、Flow 表达式、match、if-let、while-let 和重导出等语法,让开发者可以用较少的编码表达相关逻辑。多范式编程:支持函数式、命令式和面向对象等多范式编程。 阅读详情

接口用来定义一个抽象类型,它不包含数据,但可以定义类型的行为。一个类型如果声明实现某接口,并且实现了该接口中所有的成员,就被称为实现了该接口。

接口的成员可以包含:

  • 成员函数
  • 操作符重载函数
  • 成员属性

这些成员都是抽象的,要求实现类型必须拥有对应的成员实现。

接口定义

一个简单的接口定义如下:

interface I { // 'open' modifier is optional.
    func f(): Unit
}

接口使用关键字 interface 声明,其后是接口的标识符 I 和接口的成员。接口成员可被 open 修饰符修饰,并且 open 修饰符是可选的。

当接口 I 声明了一个成员函数 f 之后,要为一个类型实现 I 时,就必须在该类型中实现一个对应的 f 函数。

因为 interface 默认具有 open 语义,所以 interface 定义时的 open 修饰符是可选的。

如下面的代码所示,定义了一个 class Foo,使用 Foo <: I 的形式声明了 Foo 实现 I 接口。

在 Foo 中必须包含 I 声明的所有成员的实现,即需要定义一个相同类型的 f,否则会由于没有实现接口而编译报错。

class Foo <: I {
    public func f(): Unit {
        println("Foo")
    }
}

main() {
    let a = Foo()
    let b: I = a
    b.f() // "Foo"
}

当某个类型实现了某个接口之后,该类型就会成为该接口的子类型。

对于上面的例子,Foo 是 I 的子类型,因此任何一个 Foo 类型的实例,都可以当作 I 类型的实例使用。

在 main 中我们将一个 Foo 类型的变量 a,赋值给一个 I 类型的变量 b。然后我们再调用 b 中的函数 f,就会打印出 Foo 实现的 f 版本。程序的输出结果为:

Foo

interface 也可以使用 sealed 修饰符表示只能在 interface 定义所在的包内继承、实现或扩展该 interface。sealed 已经蕴含了 public/open 的语义,因此定义 sealed interface 时若提供 public/open 修饰符,编译器将会告警。继承 sealed 接口的子接口或实现 sealed 接口的类仍可被 sealed 修饰或不使用 sealed 修饰。若 sealed 接口的子接口被 public 修饰,且不被 sealed 修饰,则其子接口可在包外被继承、实现或扩展。继承、实现 sealed 接口的类型可以不被 public 修饰。

package A
public interface I1 {}
sealed interface I2 {}         // OK
public sealed interface I3 {}  // Warning, redundant modifier, 'sealed' implies 'public'
sealed open interface I4 {}    // Warning, redundant modifier, 'sealed' implies 'open'

class C1 <: I1 {}
public open class C2 <: I1 {}
sealed class C3 <: I2 {}
extend Int64 <: I2 {}
package B
import A.*

class S1 <: I1 {}  // OK
class S2 <: I2 {}  // Error, I2 is sealed interface, cannot be inherited here.

通过接口的这种约束能力,我们可以对一系列的类型约定共同的功能,达到对功能进行抽象的目的。

例如下面的代码,我们可以定义一个 Flyable 接口,并且让其他具有 Flyable 属性的类实现它。

interface Flyable {
    func fly(): Unit
}

class Bird <: Flyable {
    public func fly(): Unit {
        println("Bird flying")
    }
}

class Bat <: Flyable {
    public func fly(): Unit {
        println("Bat flying")
    }
}

class Airplane <: Flyable {
    public func fly(): Unit {
        println("Airplane flying")
    }
}

func fly(item: Flyable): Unit {
    item.fly()
}

main() {
    let bird = Bird()
    let bat = Bat()
    let airplane = Airplane()
    fly(bird)
    fly(bat)
    fly(airplane)
}

编译并执行上面的代码,我们会看到如下输出:

Bird flying
Bat flying
Airplane flying

接口的成员可以是实例的或者静态的,以上的例子已经展示过实例成员函数的作用,接下来我们来看看静态成员函数的作用。

静态成员函数和实例成员函数类似,都要求实现类型提供实现。

例如下面的例子,我们定义了一个 NamedType 接口,这个接口含有一个静态成员函数 typename 用来获得每个类型的字符串名称。

这样其它类型在实现 NamedType 接口时就必须实现 typename 函数,之后我们就可以安全地在 NamedType 的子类型上获得类型的名称。

interface NamedType {
    static func typename(): String
}

class A <: NamedType {
    public static func typename(): String {
        "A"
    }
}

class B <: NamedType {
    public static func typename(): String {
        "B"
    }
}

main() {
    println("the type is ${ A.typename() }")
    println("the type is ${ B.typename() }")
}

程序输出结果为:

the type is A
the type is B

接口中的静态成员函数(或属性)可以没有默认实现,也可以拥有默认实现。

当其没有默认实现时,将无法通过接口类型名对其进行访问。例如下面的代码,直接访问 NamedType 的 typename 函数会发生编译报错,因为 NamedType 不具有 typename 函数的实现。

main() {
    NamedType.typename() // Error
}

接口中的静态成员函数(或属性)也可以拥有默认实现,当另一个类型继承拥有默认静态函数(或属性)实现的接口时,该类型可以不再实现这个静态成员函数(或属性),该函数(或属性)可以通过接口名和该类型名直接访问。如下用例,NamedType 的成员函数 typename 拥有默认实现,且在 A 中都可以不用再重新实现它,同时,也可以通过接口名和该类型名对其进行直接访问。

interface NamedType {
    static func typename(): String {
        "interface NamedType"
    }
}

class A <: NamedType {}

main() {
    println(NamedType.typename())
    println(A.typename())
    0
}

程序输出结果为:

interface NamedType
interface NamedType

通常我们会通过泛型约束,在泛型函数中使用这类静态成员。

例如下面的 printTypeName 函数,当我们约束泛型变元 T 是 NamedType 的子类型时,我们需要保证 T 的实例化类型中所有的静态成员函数(或属性)都必须拥有实现,以保证可以使用 T.typename 的方式访问泛型变元的实现,达到了我们对静态成员抽象的目的。详见泛型章节。

interface NamedType {
    static func typename(): String
}

interface I <: NamedType {
    static func typename(): String {
        f()
    }
    static func f(): String
}

class A <: NamedType {
    public static func typename(): String {
        "A"
    }
}

class B <: NamedType {
    public static func typename(): String {
        "B"
    }
}

func printTypeName<T>() where T <: NamedType {
    println("the type is ${ T.typename() }")
}

main() {
    printTypeName<A>() // Ok
    printTypeName<B>() // Ok
    printTypeName<I>() // Error, 'I' must implement all static function. Otherwise, an unimplemented 'f' is called, causing problems.
}

需要注意的是,接口的成员默认就被 public 修饰,不可以声明额外的访问控制修饰符,同时也要求实现类型必须使用 public 实现。

interface I {
    func f(): Unit
}

open class C <: I {
    protected func f() {} // Compiler Error, f needs to be public semantics
}

接口继承

当我们想为一个类型实现多个接口,可以在声明处使用 & 分隔多个接口,实现的接口之间没有顺序要求。

例如下面的例子,我们可以让 MyInt 同时实现 Addable 和 Subtractable 两个接口。

interface Addable {
    func add(other: Int64): Int64
}

interface Subtractable {
    func sub(other: Int64): Int64
}

class MyInt <: Addable & Subtractable {
    var value = 0
    public func add(other: Int64): Int64 {
        value + other
    }
    public func sub(other: Int64): Int64 {
        value - other
    }
}

接口可以继承一个或多个接口,但不能继承类。与此同时,接口继承的时候可以添加新的接口成员。

例如下面的例子,Calculable 接口继承了 Addable 和 Subtractable 两个接口,并且增加了乘除两种运算符重载。

interface Addable {
    func add(other: Int64): Int64
}

interface Subtractable {
    func sub(other: Int64): Int64
}

interface Calculable <: Addable & Subtractable {
    func mul(other: Int64): Int64
    func div(other: Int64): Int64
}

这样实现类型实现 Calculable 接口时就必须同时实现加减乘除四种运算符重载,不能缺少任何一个成员。

class MyInt <: Calculable {
    var value = 0
    public func add(other: Int64): Int64 {
        value + other
    }
    public func sub(other: Int64): Int64 {
        value - other
    }
    public func mul(other: Int64): Int64 {
        value * other
    }
    public func div(other: Int64): Int64 {
        value / other
    }
}

MyInt 实现 Calculable 的同时,也同时实现了 Calculable 继承的所有接口,因此 MyInt 也实现了 Addable 和 Subtractable,即同时是它们的子类型。

main() {
    let myInt = MyInt()
    let add: Addable = myInt
    let sub: Subtractable = myInt
    let calc: Calculable = myInt
}

对于 interface 的继承,子接口如果继承了父接口中有默认实现的函数或属性,则在子接口中不允许仅写此函数或属性的声明(即没有默认实现),而是必须要给出新的默认实现,并且函数定义前的 override 修饰符(或 redef 修饰符)是可选的;子接口如果继承了父接口中没有默认实现的函数或属性,则在子接口中允许仅写此函数或属性的声明(当然也允许定义默认实现),并且函数声明或定义前的 override 修饰符(或 redef 修饰符)是可选的。

interface I1 {
   func f(a: Int64) {
        a
   }
   static func g(a: Int64) {
        a
   }
   func f1(a: Int64): Unit
   static func g1(a: Int64): Unit
}

interface I2 <: I1 {
    /*'override' is optional*/ func f(a: Int64) {
       a + 1
    }
    override func f(a: Int32) {} // Error, override function 'f' does not have an overridden function from its supertypes
    static /*'redef' is optional*/ func g(a: Int64) {
       a + 1
    }
    /*'override' is optional*/ func f1(a: Int64): Unit {}
    static /*'redef' is optional*/ func g1(a: Int64): Unit {}
}

接口实现

仓颉所有的类型都可以实现接口,包括数值类型、Rune、String、struct、class、enum、Tuple、函数以及其它类型。

一个类型实现接口有三种途径:

  1. 在定义类型时就声明实现接口,在以上的内容中我们已经见过相关例子。
  2. 通过扩展实现接口,这种方式详见扩展章节。
  3. 由语言内置实现,具体详见《仓颉编程语言库 API》相关文档。

实现类型声明实现接口时,需要实现接口中要求的所有成员,为此需要满足下面一些规则。

  1. 对于成员函数和操作符重载函数,要求实现类型提供的函数实现与接口对应的函数名称相同、参数列表相同、返回类型相同。
  2. 对于成员属性,要求是否被 mut 修饰保持一致,并且属性的类型相同。

所以大部分情况都如同上面的例子,我们需要让实现类型中包含与接口要求的一样的成员的实现。

但有个地方是个例外,如果接口中的成员函数或操作符重载函数的返回值类型是 class 类型,那么允许实现函数的返回类型是其子类型。

例如下面这个例子,I 中的 f 返回类型是一个 class 类型 Base,因此 C 中实现的 f 返回类型可以是 Base 的子类型 Sub。

open class Base {}
class Sub <: Base {}

interface I {
    func f(): Base
}

class C <: I {
    public func f(): Sub {
        Sub()
    }
}

除此以外,接口的成员还可以为 class 类型提供默认实现。拥有默认实现的接口成员,当实现类型是 class 的时候,class 可以不提供自己的实现而继承接口的实现。

注意

默认实现只对类型是 class 的实现类型有效,对其它类型无效。

例如下面的代码中,SayHi 中的 say 拥有默认实现,因此 A 实现 SayHi 时可以继承 say 的实现,而 B 也可以选择提供自己的 say 实现。

interface SayHi {
    func say() {
        "hi"
    }
}

interface SayHello {
    func say() {
        "hello"
    }
}

class Foo <: SayHi & SayHello {
    public func say() {
        "Foo"
    }
}

特别地,如果一个类型在实现多个接口时,多个接口中包含同一个成员的默认实现,这时会发生多重继承的冲突,语言无法选择最适合的实现,因此这时接口中的默认实现也会失效,需要实现类型提供自己的实现。

例如下面的例子,SayHi 和 SayHello 中都包含了 say 的实现,Foo 在实现这两个接口时就必须提供自己的实现,否则会出现编译错误。

interface SayHi {
    func say() {
        "hi"
    }
}

interface SayHello {
    func say() {
        "hello"
    }
}

class Foo <: SayHi & SayHello {
    public func say() {
        "Foo"
    }
}

struct、enum 和 class 在实现接口时,函数或属性定义前的 override 修饰符(或 redef 修饰符)是可选的,无论接口中的函数或属性是否存在默认实现。

interface I {
    func foo(): Int64 {
        return 0
    }
}
enum E <: I{
    elem
    public override func foo(): Int64 {
        return 1
    }
}
struct S <: I {
    public override func foo(): Int64 {
        return 1
    }
}

Any 类型

Any 类型是一个内置的接口,它的定义如下面。

interface Any {}

仓颉中所有接口都默认继承它,所有非接口类型都默认实现它,因此所有类型都可以作为 Any 类型的子类型使用。

如下面的代码,我们可以将一系列不同类型的变量赋值给 Any 类型的变量。

main() {
    var any: Any = 1
    any = 2.0
    any = "hello, world!"
}

写在最后

  • 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing ,不定期分享原创知识。

一文看懂分布式存储架构 目录一、集中存储结构二、分布式存储1 、分布式存储的兴起2 、分布式存储的重要性3 、分布式存储的种类和比较三、分布式理论浅析1 、一致性和可用性2 、数据分布3 、复制4 、分布式协议5、跨机房部署四、分布式文件系统1、 Google 文件系统( GFS )2、 Taobao 文件系统( TFS )3、 Fackbook Haystack 文件系统4、 CDN 内容分发网络五、分布式键值系统1、 Amazon Dynamo2、 Taobao Tiar3、 ETCD4 、产品选型比较( Etcd , Zoo 阅读详情

相关推荐

ABtest描述统计功效

我们在面试数据分析时,常常会问到如何确定样本量的问题,会有一个指标:统计功效(power),或者是1-β 统计功效会影响实验的可信度,甚至会影响实验所需的样本量,要了解统计功效,首先要理解两类统计错误 假如我们做了一个AB实验,且两组用户的数据均值为μ1和μ2,我们会有两个初始假设: H0:两个实验组的数据没有差别(μ1=μ2),这个假设也叫“零假设”,也叫原假设 H1:两个实验组之间的数据存在差别(μ1≠μ2),这个假设也叫“非零假设”,也叫备择假设 定义两类错误: 实验本身没有效应,但我们觉

qq_38134556的博客 904

跟我一起学“仓颉”编程语言-接口

本章为大家详细的介绍了仓颉编程语言中接口的内容。

Cool_foolisher的博客 934

Spring Boot日志可视化实战:5分钟搞定Promtail采集与Grafana查询(避坑指南)

本文详细介绍了如何通过Promtail和Grafana实现Spring Boot日志的可视化查询,提供从日志采集到高效查询的全流程实战指南,重点解决部署中的常见问题。内容包括Logback配置、Promtail日志采集、Grafana的LogQL查询技巧及生产环境优化建议,帮助开发者快速定位和解决日志问题。

weixin_42526015的博客 107

仓颉开发-对象

仓颉支持lambda,支持泛型,泛型类似c#.

jinyuttt的专栏 460

基于FPGA 外置qspi Flash的读写

fpga上实现flash读写代码

weixin_43498765的博客 4956

微带天线理论学习笔记(1)

微带天线的概念是由Deschamps于1953年提出来的,它是在一块厚度远小于工作波长的介质基片的一面敷以金属辐射片、一面全部敷以金属薄层作接地板而成。辐射片可以根据不同的要求设计成各种形状。微带天线具有质量轻、体积小和易于制造等优点,广泛应用于个人无线通信中。

qq_36521926的博客 6227

仓颉语言项目实战:构建一个高性能HTTP服务器(附完整代码解析)

仓颉(Cangjie)是由华为开发的静态类型、编译型系统编程语言,旨在为数字基础设施提供安全、高效和并发的编程解决方案。其设计哲学融合了现代编程语言的优秀特性,同时针对大规模系统开发进行了专门优化。// 基本函数x + y // 隐式返回(无分号)// 显式返回// 泛型函数max = item;Some(max)// 高阶函数wheref(f(x))println!println!("最大值: {}", max),("数组为空"),// 使用高阶函数。

2501_93045689的博客 1105

C#实战:手把手教你用SerialPort实现RS485 ModbusRTU通信(附完整代码)

本文详细介绍了如何使用C#的SerialPort类实现RS485 ModbusRTU通信,包括硬件准备、串口配置、数据收发核心逻辑及高级通信技巧。通过实战案例和完整代码,帮助开发者快速掌握工业级通信框架的构建方法,提升设备间通信的稳定性和效率。

weixin_29207533的博客 257

仓颉编程语言 -- 初识(一)

仓颉编程语言 -- 初识(一)

chinusyan的专栏 3025

vue2学习笔记2-老规矩,从Hello World开始,了解Vue实例和模板

想要把“Hello,World”放置在页面上,首先需要准备一个HTML的块级元素div,来承接内容。

l_q_l的专栏 1259

反应动力学仿真软件:ChemkinPro_(11).敏感性分析

敏感性分析是化学反应动力学仿真中的一项重要技术,通过对模型参数的变化对模型输出的影响进行评估,可以帮助研究人员优化模型、验证实验数据和评估不确定性。ChemkinPro 提供了强大的敏感性分析功能,可以方便地进行参数选择、仿真设置和结果解读。通过实际案例研究,我们可以看到敏感性分析在燃烧、催化和环境化学等领域的广泛应用,为科学研究和工程应用提供了有力支持。

kkchenjj的博客 1310

仓颉编程语言中的HTTP与WebSocket编程详解

简洁的API设计:通过构建器模式和高层抽象简化开发协议完整性:全面支持HTTP/1.1、HTTP/2和WebSocket协议性能优化:内置连接池、压缩等优化手段安全内置:提供TLS、认证等安全功能可扩展架构:支持中间件、过滤器等扩展点掌握这些网络编程技术,开发者可以高效构建Web服务、实时通信系统等各类网络应用。建议从简单示例开始,逐步深入理解协议细节和高级特性,最终开发出高性能、高可靠的网络服务。

Huang兄 786

Pareto 优化 (Pareto Optimization) 算法详解及案例分析

Pareto 最优解是指在多目标优化问题中,无法通过改进一个目标而不损害其他目标的解。具体来说,对于一个解x∗x^*x∗,如果不存在另一个解xxx使得所有目标函数fixf_i(x)fi​x都不劣于fix∗f_i(x^*)fi​x∗,且至少有一个目标函数fjxf_j(x)fj​x优于fjx∗f_j(x^*)fj​x∗,则x∗x^*x∗是 Pareto 最优解。

闲人编程的博客 2765

仓颉编程语言:接口扩展

当使用扩展为 Array 实现 PrintSizeable 之后,就相当于在 Array 定义时实现接口 PrintSizeable。

Androidbye的博客 1222

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

仓颉编程语言青少年基础教程:Interface(接口)

本文介绍了仓颉编程语言中的接口(Interface)概念及其应用。和Any类型作为所有类型的隐式父接口的特性。

cnds123的专栏 1172

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

仓颉编程语言:泛型接口

泛型可以用来定义泛型接口..........

Androidbye的博客 727

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

解锁仓颉编程语言的奥秘:枚举类型、模式匹配与类接口全解析

Red,Green,Blue,// 输出: Green模式是仓颉语言中用于结构化解构和匹配的数据描述方式。字面量模式枚举模式结构模式通配符模式仓颉语言中的类支持面向对象的建模,包含属性和方法。// 输出: Hello, my name is Alicec.draw();本文深入剖析了仓颉编程语言的基础数据类型及其高级用法,并通过代码示例展示了每种类型的实际应用场景。

2301_80863610的博客 1923

仓颉编程语言中的接口定义与实现:抽象设计的深度实践

我们可以定义不同层次的接口来描述设备的能力:基础的Identifiable接口定义设备标识能力,Controllable接口定义可控制设备的启停方法,Monitorable接口定义状态监控能力,Configurable接口定义配置管理能力。在鸿蒙的分布式场景中,不同设备的同类对象可能有不同的实现,但它们都实现了统一的接口,这让跨设备的协同变得透明和高效。在鸿蒙生态的全场景应用开发中,不同设备可能需要不同的实现策略,而接口机制让这种差异化实现变得自然而清晰。接口中的方法默认是公开的,实现类不能降低访问级别。

2301_82226308的博客 844

跟我一起学“仓颉”编程语言-扩展练习题

本章为大家详细的介绍了仓颉编程语言中扩展练习题的内容。

Cool_foolisher的博客 419

跟我一起学“仓颉”编程语言-抽象类和接口练习题

本章为大家详细的介绍了仓颉编程语言中类和接口练习题的内容

Cool_foolisher的博客 587

仓颉编程(11)类三大特性的解析

在面向对象编程中,封装(Encapsulation)是将对象的属性和方法结合在一起,并隐藏对象的内部实现细节,只通过公开的接口与外部交互。封装是面向对象编程的三大核心特性之一(封装、继承、多态),其本质是 "隐藏对象的内部实现细节,仅通过预定义的公共接口暴露交互能力"。在仓颉编程语言中,封装机制通过访问修饰符实现对类成员的精细控制。提高数据访问的安全性:通过将成员变量声明为私有,阻止外部直接访问和修改,确保数据的完整性和一致性实现信息隐藏。

sucker的博客 818

跟我一起学“仓颉”设计模式-面向对象设计原则

本章为大家详细的介绍了仓颉设计模式中面向对象设计原则的内容。

Cool_foolisher的博客 581

跟我一起学“仓颉”编程语言-mut函数

本章为大家详细的介绍了仓颉编程语言中mut函数的内容。

Cool_foolisher的博客 581

跟我一起学“仓颉”设计模式-外观模式

本章为大家详细的介绍了仓颉设计模式中外观模式的内容。

Cool_foolisher的博客 408

初识仓颉编程语言

初识仓颉编程语言

qq1309399183的博客 1323

仓颉编程语言入门

五年磨一剑,华为仓颉编程语言正式发布。

程小二的博客 4万+
上一篇: 仓颉编程语言:类
下一篇: 仓颉编程语言:属性
懂你的大海
博客等级 码龄6年 9049粉丝 1381原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值