nim 语言使用 concept 实现 c# 的interface
nim简介
nim语言兼顾C#等高级语言语义表达的丰富性,又有 C 语言的灵活性,以及超强的性能。下面是中文站对他的总结,我抄下来:
Nim 是一种静态类型的、编译型、系统编程语言。
它结合了其他成熟语言的成功概念。
(如 Python、Ada 和 Modula)
效率
- Nim 生成原生且无依赖的可执行文件,不依赖于虚拟机,
所以它们小巧易分发。 - Nim 编译器和生成的可执行文件,对目前的任何主流平台都提供了支持,
包括 Windows、Linux、BSD 和 macOS。 - Nim 的内存管理是确定性的,可使用析构函数和移动语义进行自定义, 其灵感来自C++和Rust。 非常适合嵌入式硬实时系统。
- 零开销迭代器和用户自定义方法的编译期求值等现代概念,
结合优先使用分配在栈上的值类型数据,生成高性能代码。 - 支持各种后端:可以被编译为 C、C++ 或 JavaScript, 以便 Nim 可用于所有后端和前端需求。
表现力
- Nim 实现了自举:编译器和标准库都是用 Nim 本身来实现的。
- Nim 拥有强大的宏系统,允许直接操纵 AST,提供无限的可能性。
优雅
- 宏不会改变 Nim 的语法,因为并没有这个必要
—— Nim 语法本身已经足够灵活。 - 具有局部类型推断、元组、泛型和sum类型的现代类型系统。
- 语句按缩进分组,也可以跨行。
接口
我满怀信心的开始学习 nim 语言,之前有 c# 和 kotlin 的编程经验,所以自然会将面向对象的思路带到 nim 中,看官方文档,继承功能完全是内建的,所以没有遇到什么困难,结果在 接口 interface 问题上卡壳了。
查询很多的资料,有几种解法,一种是官方库中 stream 的解法,要定义一个 stream 和一个 streamObj ,然后在实现类中一一映射,我觉得太麻烦,直接放弃了。
还有一篇文章介绍了利用 nim 的宏功能,自己造了一个轮子,我觉得主要的问题是,不是官方支持的,我如果写了大量的代码,有问题不好解决,而且有更好的官方方案的话,就要大量重写。况且,他构建了 vTable ,有间接调用成本。
但是,功夫不负有心人,我终于找到官方的解决方案,使用 concept 来解决 interface 的问题, concept 中文翻译为 概念,有点拗口,我的理解是,定义一堆约束,如果某个类符合这个约束,那么就自然可以使用这个约束来访问,这不就是 interface 想要表达的意思吗?
但我觉得 nim 设计 concept 时,思想比 interface 更进一步,就是鸭子类型(duck typing)的概念,即如果它走起路来像鸭子,叫起来也是鸭子,那么它就是鸭子。
下面是定义 concept (接口) 的方法:
type
# 定义一个 IImmutableList<E> 这样的接口,在nim中叫 概念
IImmutableList[E] = concept self # 包含一个方法,允许用 var a = obj[32] 这样的方式索引访问。
self.`[]`(uint64) is E # 定义了一个 size 只读属性
self.size is uint64
然后你就可以写自己的类了,只要你的方法和签名与接口一致就可以了,不需要像 c# 或 kotlin ,java 那样要显式的写实现了此接口。
type
SeqImmutableList[E] = ref object of RootObj
items : seq[E] # 为 SeqImmutableList 定义了一个 size 属性
proc size*[E](this: SeqImmutableList[E]) : uint64 {.inline.} =
uint64(this.items.len) #用到类型转换 # 定义一个可以直接使用 [] 方式访问的方法。
proc `[]`*[E](this: SeqImmutableList[E], index : uint64) : E {.inline.} =
this.items[int(index)] # 相当于构造函数,只有构造函数才能访问私有变量。
proc newSeqImmutableList*[E](items : seq[E]) : SeqImmutableList[E] =
new(result)
result.items = items let target = newSeqImmutableList(@[1,2,3,4])
echo "size = ", target.size
echo "target[2] = ", target[2]
到目前,上面的代码仍然是类自己的方法去访问的,但是你想使用接口的方式访问,非常的方便,直接传递就可以了。
# 以接口(概念)的方式访问
proc printAll(this: IImmutableList) =
echo "size = ", this.size
for i in 0..<this.size:
echo "items[", i, "] = ", this[i] printAll(target)
这里我将 target (他是SeqImmutableList<int>类型)直接传递给 printAll 方法,编译器只要觉得符合 概念(concept),就可以传递。
接口的继承
如果我现在想定义一个新的接口,派生自原来的接口怎么办呢?
IMutableList[E] = concept self
# 相当于c# 的继承
self is IImmutableList[E] # 提供按索引更改的能力,类似 c# 的 this[i] = x 这样的赋值。
self.`[]=`(idx,E)
使用 is ... 表达了继承的概念,然后再编写你新的想定义的方法。
现在,我们新定义一个类,让他两个接口都支持,当然,我们顺便也学习一下对象继承的写法。
type
SeqMutableList[E] = ref object of SeqImmutableList[E]
isDirty : bool # 提供按索引的写
proc `[]=`[E](this: SeqMutableList, index:idx, value : E) =
this.elements[int(index)] = value proc newSeqMutableList[E](items : seq[E]) : SeqMutableList[E] =
return SeqMutableList[E](elements:items, isDirty:false)
现在,你可以按照类本身 SeqMutableList[E] 的方式访问他,也可以使用两个接口 IImmutableList[E] 和 IMutableList[E] 的方式,也可以使用基类 SeqImmutableList 的方式访问
# 创建可变的对象
let target2 = newSeqMutableList(@[1,2,3,4,5])
echo "size2 = ", target2.size #访问基类的方法 # 修改他的值,并使用基类提供的方法重新获取
target2[2] = 99
echo "target2[2] = ", target2[2] # 可以传递给基准的接口去访问。
printAll(target2) # 可变的接口访问,包含基类的方法。
let target3 : IMutableList[int] = target2
echo "size3 = ", target3.size
target3[2] = 9999
echo "target3[2] = ", target3[2]
echo "target2[2] = ", target2[2]
let target4 : SeqImmutableList[int] = target2
echo "target4[2] = ", target4[2]
概念除了可以作为接口使用,还可以对泛型约束,更多复杂的使用方法,参见:https://nim-lang.org/docs/manual_experimental.html#concepts
nim 语言使用 concept 实现 c# 的interface的更多相关文章
- Nim语言的模块化编程
前言 Nim支持把一大段程序分成若干个模块 一个模块就是一个源代码文件 每个模块都拥有它自己的名称空间 模块化可以起到封装(信息隐藏)和分步编译的作用 一个模块可以通过import语句获得另一个模块的 ...
- 学习Nim语言.rar(nim语言中文教程下载)
学习Nim语言 nim 语法上类似python ,是一门静态编译型语言,nim 使用空格缩进标示语句块的开始和结束, 喜欢python风格的程序员应该也会很容易适应和喜欢nim的风格. nim语言官方 ...
- Nim语言:Pascal的语法,Python的缩进
http://nim-lang.org/ 德国人Andreas Rumpf的作品,原因是他对过去使用的每种语言都不满意(Pascal也不满意?).以前叫Nimrod语言,从0.96版本开始改名为Nim ...
- GO学习-(38) Go语言结构体转map[string]interface{}的若干方法
结构体转map[string]interface{}的若干方法 本文介绍了Go语言中将结构体转成map[string]interface{}时你需要了解的"坑",也有你需要知道的若 ...
- 用Nim语言开发windows GUI图形界面程序
前言 本文得到了“樂師”的大力支持, 我们一起调试程序到深夜,要是没有他的帮忙, 我不知道要多久才能迈过这道坎, 另外“归心”还有其他人也提供了帮助, 他们都来自于QQ群:“Nim开发集中营”4693 ...
- nim的引用和指针
nim语言的引用和其他语言的指针有点相似 可以提供一种“多对一”的关系 这就意味着不同的引用可以指向同一个内存位置 nim区分可被追踪的引用和不可被追踪的引用 不可被追踪的引用又称为指针 可被追踪的引 ...
- Nim编码风格
介绍 Nim语言不限制开发人员使用哪种具体的编码风格, 但为了社区的发展,在编写一些标准库的时候还是应该遵从统一的编码风格 这篇文章会列出一系列的编码风格准则,供大家参考. 但值得注意的是,有很多例外 ...
- Nim教程【十五】【完结】
模版 模版是Nim语言中的抽象语法树,它是一种简单的替换机制,在编译期被处理 这个特性使Nim语言可以和C语言很好的运行在一起 像调用一个方法一样调用一个模版 请看如下代码: template `!= ...
- Nim教程【十四】
网友@沉没捕鱼,赞助了一台服务器 这个系列的教程写完之后,我们就要开始着手搭建Nim的社区了~ 异常 Nim中的异常类型是对象类型 根据惯例,Nim中的异常类型的命名都应该以Error后缀结尾 在sy ...
- Nim教程【九】
向关注这个系列的朋友们,道一声:久违了! 它并没有被我阉掉,他一定会得善终的,请各位不要灰心 Set集合类型 为了在特殊场景下提高程序的性能设置了Set类型,同时也是为了保证性能,所以Set只能容纳有 ...
随机推荐
- .NET周刊【1月第4期 2025-01-26】
国内文章 低成本高可用方案!Linux系统下SQL Server数据库镜像配置全流程详解 https://www.cnblogs.com/lyhabc/p/18660810/linux-sql-ser ...
- What?废柴, 还在本地部署DeepSeek吗?Are you kidding?
前言 DeepSeek推出更强大的推理模型DeepSeek R1后一发不可收拾,迅速火遍全球,用户暴增,但巨大的流量以及一些不可控因素,DeepSeek官网变得极不稳定,经常出现"网络繁忙& ...
- Vue 组件里添加键盘事件 keydown keyup不生效问题
我在使用VueDraggableResizable制作一个窗口,然后需要点击esc关闭窗口. 但是键盘事件没有生效,写任何位置都不行. 解决方案 在需要触发esc事件的div或其他上给出 tabind ...
- MySQL Q&A - [01] root密码忘记了怎么办
题记部分 Windows 场景下 1.先使用管理员身份打开两个命令提示符窗口(winA和winB) 2.在命令提示符窗口winA中将MySQL服务停掉net stop mysql Microsoft ...
- [AI/GPT/LLOps/AI中台] Dify : 开源AI大模型应用开发平台(Apache 2.0)
概述:Dify Dify 是一款开源的大语言模型(LLM) 应用开发平台. 它融合了后端即服务(Backend as Service)和 LLMOps 的理念,使开发者可以快速搭建生产级的生成式 AI ...
- minecraft mods descrip
1. [Advanced Finders]矿物探测器 mod 显示玩家周围附近矿石的方向(指针显示水平面上可到达的矿石) 探测地下深部矿脉(箭头显示最近矿脉的方向(上/下)) 发现大型矿床时发出信号( ...
- Redmine 中,如何新增一个字段名,比如"模块名称":
why: 用于编写测试报告时能够直接根据模块名称进行统计,不对excel 表格进行自定义拆分-----规范性 登录到 Redmine 平台,并进入你的项目页面. 在项目页面上方的导航栏中,点击 &qu ...
- Manus的开源复刻OpenManus初探
OpenManus介绍 Manus需要邀请码才能体验,目前大部分人都体验不到. 有几个大佬花3个小时就复现了一个简单的原型OpenManus,让我们体验体验吧!! 截至目前,该项目已经获得了25.9k ...
- js回忆录(1) -- 变量,null 和 undefined
变量:这个东西不同的高度的人看法不一样,甚至不同领域的人的看法也不一样,当初上机组的时候依稀记得老师说这个寄存器那个锁存器什么的,然后根据高低电位就变成了二进制认识的0和1了,当然了具体细节本博主大人 ...
- 超级详细的mysql数据库安装指南
https://zhuanlan.zhihu.com/p/37152572 2,073 人赞同了该文章 如果你的电脑是mac,参考社群会员 @奔跑的土豆 的分享: mac下mysql的安装步骤 227 ...