仓颉语言中sealed 修饰符介绍

仓颉语言中sealed 修饰符介绍

以下是官方文档节选:

抽象类总是可被继承的,故抽象类定义时的 open 修饰符是可选的,也可以使用 sealed 修饰符修饰抽象类,表示该抽象类只能在本包被继承。

抽象类可以使用 sealed 修饰符,表示被修饰的类定义只能在本定义所在的包内被其他类继承。sealed 已经蕴含了 public/open 的语义,因此定义 sealed abstract class 时若提供 public/open 修饰符,编译器将会告警。sealed 的子类可以不是 sealed 类,仍可被 open/sealed 修饰,或不使用任何继承性修饰符。若 sealed 类的子类被 open 修饰,则其子类可在包外被继承。sealed 的子类可以不被 public 修饰。

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

官方示例也很简短。

【官方文档详见

https://cangjie-lang.cn/docs?url=%2F1.0.0%2Fuser_manual%2Fsource_zh_cn%2Fclass_and_interface%2Fclass.html

https://cangjie-lang.cn/docs?url=%2F1.0.0%2Fuser_manual%2Fsource_zh_cn%2Fclass_and_interface%2Finterface.html

不太好明白,现探索实践验证介绍如下。

顺便说明,在仓颉语言中,sealed 修饰符属于非访问修饰符(也称为 “功能修饰符”),而非访问修饰符(如 public、private 等)。

sealed 在抽象类中的使用示例

sealed修饰抽象类的核心是 “限制自身的继承范围在本包内”,但允许子类通过open等修饰符打破这个限制,兼顾了封装性和灵活性。

  •  同包内的继承、实现、多级继承和方法重写均合法,程序可正常运行并输出预期结果。

  •  跨包的继承 / 实现尝试会在编译阶段被拦截,确保密封类型的实现范围被严格控制在设计的包内,增强代码封装性。

示例项目结构(包结构):

demo/
└── src
    ├─sealed
    │   ├── SamePackageImplementations.cj       
    │   └── SealedTypes.cj  
    ├─other
    │   └── DifferentPackageAttempt.cj 
    └── main.cj            // 入口

1.sealed/SealedTypes.cj内容如下:

package demo.sealed 

// 定义sealed抽象类
sealed abstract class SealedClass {
    //public init() {}                // 空参构造
    public func hello(): String {
        return "Hello from SealedClass" 
    }
    
    public func whoAmI(): String 
}

// 定义sealed接口
sealed interface SealedInterface {    
    func doSomething(): Unit 
}

2.sealed/SamePackageImplementations.cj 内容如下:

package demo.sealed 

// 同包内继承sealed类(合法)
public class SamePackageClass <: SealedClass {
    public func whoAmI(): String {
        return "I'm SamePackageClass (extends SealedClass)" 
    }
}

// 同包内实现sealed接口(合法)
public class SamePackageInterfaceImpl <: SealedInterface {
    public func doSomething(): Unit {
        println("SamePackageInterfaceImpl is doing something") 
    }
}

// 同包内继承并开放给同包进一步继承
public open class OpenSamePackageClass <: SealedClass {
    // 关键:给方法添加 open,允许子类重写
    public open func whoAmI(): String {  
        return "I'm OpenSamePackageClass (extends SealedClass)" 
    }
}

// 同包内继承开放类(现在合法)
public class AnotherSamePackageClass <: OpenSamePackageClass {
    public override func whoAmI(): String {  // 此时 override 有效
        return "I'm AnotherSamePackageClass (extends OpenSamePackageClass)" 
    }
}

3.other/DifferentPackageAttempt.cj 内容如下:

package demo.other 

import demo.sealed.SealedClass 
import demo.sealed.SealedInterface 
import demo.sealed.OpenSamePackageClass 

// // 尝试在不同包继承sealed类(不合法)
// class DifferentPackageClass <: SealedClass {  // 编译错误:无法继承sealed类
//     public func whoAmI(): String {
//         return "This won't compile" 
//     }
// }

// // 尝试在不同包实现sealed接口(不合法)
// class DifferentPackageInterfaceImpl <: SealedInterface {  // 编译错误:无法实现sealed接口
//     public func doSomething(): Unit {
//         println("This won't compile either") 
//     }
// }

// // 尝试在不同包继承sealed类的同包子类(不合法)
// class DifferentPackageExtendsOpen <: OpenSamePackageClass {  // 编译错误:即使父类是open的,也不能跨包继承
//     public override func whoAmI(): String {
//         return "This won't compile too" 
//     }
// }

4.入口文件 main.cj内容如下:

package demo

import demo.sealed.SamePackageClass 
import demo.sealed.SamePackageInterfaceImpl 
import demo.sealed.AnotherSamePackageClass
 
main() {
    // 测试同包内的sealed类继承
    let obj1 = SamePackageClass() 
    println(obj1.hello()) 
    println(obj1.whoAmI()) 
    
    // 测试同包内的sealed接口实现
    let obj2 = SamePackageInterfaceImpl() 
    obj2.doSomething() 
    
    // 测试同包内的多级继承
    let obj3 = AnotherSamePackageClass() 
    println(obj3.whoAmI()) 
}

运行截图:

说明:

1. sealed 修饰符的核心作用

  •  限制跨包继承 / 实现:被 sealed 修饰的类或接口,只能在当前包内被继承(类)或实现(接口),跨包尝试会直接编译报错。

         示例中,demo.sealed 包的 SealedClass(密封类)和 SealedInterface(密封接口),在 demo.other 包中无法被继承或实现。

2. 同包内的合法操作

  •  同包继承密封类:在 demo.sealed 包内,SamePackageClass 和 OpenSamePackageClass 可以直接继承 SealedClass(合法)。

  •  同包实现密封接口:SamePackageInterfaceImpl 在 demo.sealed 包内实现 SealedInterface(合法)。

  •  同包多级继承:密封类的子类(如 OpenSamePackageClass)若被 open 修饰,允许在同包内被进一步继承(如 AnotherSamePackageClass 继承 OpenSamePackageClass)。

3. 跨包的禁止操作

  •  无法在其他包(如 demo.other)继承密封类(SealedClass)或其同包子类(OpenSamePackageClass)。

  •  无法在其他包实现密封接口(SealedInterface)。

  •  即使密封类的子类被 open 修饰(如 OpenSamePackageClass),跨包继承依然被禁止(sealed 限制具有传递性)。

4.还需要注意:方法重写的严格规则

  •  open 与 override 配对使用:

         父类方法必须用 open 修饰,才能允许子类重写(如 OpenSamePackageClass 中的 open func whoAmI())。

         子类重写父类方法时,必须显式添加 override 关键字(如 AnotherSamePackageClass 中的 override func whoAmI())。

  •  若父类方法未加 open,即使类被 open 修饰,子类也无法重写该方法(会触发编译错误)。

sealed 在接口中的使用示例

示例项目(包)结构

demo9/
└── src
    ├─A
    │   ├── a1.cj       
    │   └── a2.cj 
    ├─B
    │   └── b1.cj 
    └── main.cj            // 入口

A/a1.cj 源码

// 包A中定义sealed接口
sealed interface Secret {
    func getSecret(): Unit //String
}

A/a2.cj 源码

// 同包内可实现
public class ASecret <: Secret {   
    public override func getSecret(): Unit {
        println("A的秘密") 
    }
}

B/b1.cj 源码

// 包B中尝试实现
package demo9.B
import demo9.A.*

// (编译报错,故注释掉)
// class BSecret <: Secret {  // 错误:sealed接口不允许跨包实现
//     public override func getSecret():  Unit {
//         println("B的秘密")
//     }
// }

入口main.cj源码

package demo9

import demo9.A.ASecret

// 主函数
main() {
    let ok = ASecret()
    ok.getSecret()     // 正常输出: A的秘密
}

运行截图:

顺便提示
若将此实例中函数的类型Unit改为String,将报错。原因是
接口方法的签名一致性:实现类重写接口方法时,返回类型必须与接口中定义的完全一致。
Unit 与 String 的区别:
  •  Unit 表示 “无返回值”(类似其他语言的 void),方法中可通过 println 输出内容,但无需 return。
  •  String 要求方法必须通过 return 语句返回一个字符串,否则会报错。

需要如下修改:

 A/a1.cj 修正为:
package demo9.A

// 接口方法返回String
sealed interface Secret {
    func getSecret(): String
}

 A/a2.cj 修正为:
// 实现类方法也返回String,与接口匹配
public class ASecret <: Secret {   
    public override func getSecret(): String {
        return "A的秘密"  // 返回String,而非仅打印
    }
}

 main.cj 修正为:
package demo9

import demo9.A.ASecret

main() {
    let ok = ASecret()
    println(ok.getSecret())  // 输出: A的秘密(打印返回的String)
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学习&实践爱好者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值