首页 > 其他分享 >无涯教程-D语言 - 范围(Ranges)

无涯教程-D语言 - 范围(Ranges)

时间:2023-11-18 11:06:04浏览次数:48  
标签:std 教程 const int 无涯 Ranges range return first

范围range是元素访问的抽象,范围强调如何访问容器元素,而不是如何实现容器。

Number ranges

数字范围是非常常用,这些数字范围是int类型的,下面是一些数字范围的示例-

//示例1
foreach (value; 3..7)  

//示例2
int[] slice=array[5..10];

Phobos Ranges

与结构和类接口有关的范围是phobos ranges, Phobos是D语言编译器随附的官方运行时和标准库。

有多种类型的范围,包括-

  • InputRange
  • ForwardRange
  • BidirectionalRange
  • RandomAccessRange
  • OutputRange

InputRange

最简单的范围是输入范围,其他范围对它们所基于的范围提出了更高的要求,InputRange需要三个函数-

  • empty        -  指定范围是否为空,当范围被认为是空时,返回true;否则为false。

  • front          -  在范围的开头提供对元素的访问。

  • popFront   -  通过删除第一个元素,从头开始缩短范围。

import std.stdio; 
import std.string; 
 
struct Student { 
   string name; 
   int number; 
   
   string toString() const { 
      return format("%s(%s)", name, number); 
   } 
}
  
struct School { 
   Student[] students; 
}
struct StudentRange {
   Student[] students; 
   
   this(School school) { 
      this.students=school.students; 
   } 
   @property bool empty() const { 
      return students.length == 0; 
   } 
   @property ref Student front() { 
      return students[0]; 
   } 
   void popFront() { 
      students=students[1 .. $]; 
   } 
}

void main() { 
   auto school=School([ Student("Raj", 1), Student("John", 2), Student("Ram", 3)]);
   auto range=StudentRange(school); 
   writeln(range);  
   
   writeln(school.students.length);
   
   writeln(range.front); 
   
   range.popFront;  
   
   writeln(range.empty); 
   writeln(range); 
}

编译并执行上述代码后,将产生以下输出-

[Raj(1), John(2), Ram(3)] 
3 
Raj(1) 
false 
[John(2), Ram(3)]

ForwardRange

ForwardRange另外还需要InputRange的其他三个函数中的save函数,并在调用save函数时返回范围range的副本。

import std.array; 
import std.stdio; 
import std.string; 
import std.range;

struct FibonacciSeries { 
   int first=0; 
   int second=1; 
   enum empty=false;   //无限范围
   
   @property int front() const { 
      return first; 
   } 
   void popFront() { 
      int third=first + second; 
      first=second; 
      second=third; 
   }
   @property FibonacciSeries save() const { 
      return this; 
   } 
}
  
void report(T)(const dchar[] title, const ref T range) {
   writefln("%s: %s", title, range.take(5)); 
} 

void main() { 
   auto range=FibonacciSeries(); 
   report("Original range", range);
   
   range.popFrontN(2); 
   report("After removing two elements", range); 
   
   auto theCopy=range.save; 
   report("The copy", theCopy);
   
   range.popFrontN(3); 
   report("After removing three more elements", range); 
   report("The copy", theCopy); 
}

编译并执行上述代码后,将产生以下输出-

Original range: [0, 1, 1, 2, 3] 
After removing two elements: [1, 2, 3, 5, 8] 
The copy: [1, 2, 3, 5, 8] 
After removing three more elements: [5, 8, 13, 21, 34] 
The copy: [1, 2, 3, 5, 8]

BidirectionalRange

除了ForwardRange函数外,BidirectionalRange还提供了两个函数,popBack函数类似于popFront函数,它从范围中删除最后一个元素。

import std.array; 
import std.stdio; 
import std.string; 

struct Reversed { 
   int[] range; 
   
   this(int[] range) { 
      this.range=range; 
   } 
   @property bool empty() const { 
      return range.empty; 
   }
   @property int front() const { 
      return range.back;  //逆转 
   }
   @property int back() const { 
      return range.front; //逆转 
   } 
   void popFront() { 
      range.popBack(); 
   }
   void popBack() { 
      range.popFront(); 
   } 
} 
 
void main() { 
   writeln(Reversed([ 1, 2, 3])); 
} 

编译并执行上述代码后,将产生以下输出-

[3, 2, 1]

Infinite RandomAccessRange

与ForwardRange相比,还需要opIndex(),同样,在编译时将空函数的值称为false。

import std.array; 
import std.stdio; 
import std.string; 
import std.range; 
import std.algorithm; 

class SquaresRange { 
   int first;  
   this(int first=0) { 
      this.first=first; 
   }
   enum empty=false; 
   @property int front() const { 
      return opIndex(0); 
   }
   void popFront() { 
      ++first; 
   }
   @property SquaresRange save() const { 
      return new SquaresRange(first); 
   }
   int opIndex(size_t index) const { 
      /* 此功能以恒定时间运行 */
      immutable integerValue=first + cast(int)index; 
      return integerValue * integerValue; 
   } 
}
  
bool are_lastTwoDigitsSame(int value) { 
   /* 必须至少有两位数字 */
   if (value < 10) { 
      return false; 
   } 
   
   /* 最后两位数字必须能被 11 整除 */
   immutable lastTwoDigits=value % 100; 
   return (lastTwoDigits % 11) == 0; 
} 
 
void main() { 
   auto squares=new SquaresRange(); 
   
   writeln(squares[5]);
   
   writeln(squares[10]); 
   
   squares.popFrontN(5); 
   writeln(squares[0]); 
   
   writeln(squares.take(50).filter!are_lastTwoDigitsSame); 
}

编译并执行上述代码后,将产生以下输出-

25 
100 
25 
[100, 144, 400, 900, 1444, 1600, 2500]

Finite RandomAccessRange

与Bidirectional range相比,还需要opIndex()和length。这将在使用斐波那契数列和先前使用的Squares Range示例进行解释。

import std.array; 
import std.stdio; 
import std.string; 
import std.range; 
import std.algorithm; 

struct FibonacciSeries { 
   int first=0; 
   int second=1; 
   enum empty=false;   //无限范围 
   
   @property int front() const { 
      return first;
   }
   void popFront() { 
      int third=first + second; 
      first=second; 
      second=third; 
   }
   @property FibonacciSeries save() const { 
      return this; 
   } 
}
  
void report(T)(const dchar[] title, const ref T range) { 
   writefln("%40s: %s", title, range.take(5)); 
}
  
class SquaresRange { 
   int first;  
   this(int first=0) { 
      this.first=first; 
   } 
   enum empty=false; 
   @property int front() const { 
      return opIndex(0); 
   }
   void popFront() { 
      ++first; 
   }
   @property SquaresRange save() const { 
      return new SquaresRange(first); 
   } 
   int opIndex(size_t index) const { 
      /* 此功能以恒定时间运行 */
      immutable integerValue=first + cast(int)index; 
      return integerValue * integerValue; 
   } 
}
  
bool are_lastTwoDigitsSame(int value) { 
   /* 必须至少有两位数字 */
   if (value < 10) { 
      return false; 
   }
   
   /* 最后两位数字必须能被 11 整除 */
   immutable lastTwoDigits=value % 100; 
   return (lastTwoDigits % 11) == 0; 
}
  
struct Together { 
   const(int)[][] slices;  
   this(const(int)[][] slices ...) { 
      this.slices=slices.dup;  
      clearFront(); 
      clearBack(); 
   }
   private void clearFront() { 
      while (!slices.empty && slices.front.empty) { 
         slices.popFront(); 
      } 
   } 
   private void clearBack() { 
      while (!slices.empty && slices.back.empty) { 
         slices.popBack(); 
      } 
   }
   @property bool empty() const { 
      return slices.empty; 
   } 
   @property int front() const { 
      return slices.front.front; 
   }
   void popFront() { 
      slices.front.popFront(); 
      clearFront(); 
   }
   @property Together save() const { 
      return Together(slices.dup); 
   } 
   @property int back() const { 
      return slices.back.back; 
   } 
   void popBack() { 
      slices.back.popBack(); 
      clearBack(); 
   }
   @property size_t length() const { 
      return reduce!((a, b) => a + b.length)(size_t.init, slices); 
   }
   int opIndex(size_t index) const { 
      /* 保存错误信息的索引 */
      immutable originalIndex=index;  

      foreach (slice; slices) { 
         if (slice.length > index) { 
            return slice[index];  
         } else { 
            index -= slice.length; 
         } 
      } 
      throw new Exception( 
         format("Invalid index: %s (length: %s)", originalIndex, this.length));
   } 
}
void main() { 
   auto range=Together(FibonacciSeries().take(10).array, [ 777, 888 ],
      (new SquaresRange()).take(5).array); 
   writeln(range.save); 
}

编译并执行上述代码后,将产生以下输出-

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 777, 888, 0, 1, 4, 9, 16]

OutputRange

OutputRange表示流元素输出,类似于将字符发送到stdout,OutputRange需要支持put(range,element)操作,put()是在std.range模块中定义的函数。它在编译时确定范围和元素的函数,并使用最合适的方法来输出元素,一个简单的例子如下所示。

import std.algorithm; 
import std.stdio; 
 
struct MultiFile { 
   string delimiter;
   File[] files;
   
   this(string delimiter, string[] fileNames ...) { 
      this.delimiter=delimiter; 

      /* 始终包含标准输出 */
      this.files ~= stdout; 

      /* 每个文件名的 File 对象 */
      foreach (fileName; fileNames) { 
         this.files ~= File(fileName, "w"); 
      } 
   }
   void put(T)(T element) { 
      foreach (file; files) { 
         file.write(element, delimiter); 
      } 
   }
}
void main() { 
   auto output=MultiFile("\n", "output_0", "output_1"); 
   copy([ 1, 2, 3], output);  
   copy([ "learnfk", "toolfk", "chromefk" ], output); 
} 

编译并执行上述代码后,将产生以下输出-

[1, 2, 3] 
["learnfk", "toolfk", "chromefk"]

参考链接

https://www.learnfk.com/d-programming/d-programming-ranges.html

标签:std,教程,const,int,无涯,Ranges,range,return,first
From: https://blog.51cto.com/u_14033984/8459614

相关文章

  • Kafka入门教程与详解(一)
    Kafka入门教程与详解(一)一、Kafka入门教程1.1消息队列(MessageQueue)MessageQueue消息传送系统提供传送服务。消息传送依赖于大量支持组件,这些组件负责处理连接服务、消息的路由和传送、持久性、安全性以及日志记录。消息服务器可以使用一个或多个代理实例。JMS(JavaMessaging......
  • 无涯教程-D语言 - 数组(Arrays)
    D编程语言提供了一种名为arrays的数据结构,该数据结构存储相同类型元素的固定大小的顺序集合,数组用于存储数据集合。声明数组要使用D编程语言声明数组,程序员可以指定元素的类型和数组所需的元素数量,如下所示:typearrayName[arraySize];这称为一维数组,arraySize必须是......
  • 无涯教程-D语言 - 字符串(Strings)
    字符数组我们可以用以下两种形式来表示字符数组.第一种形式直接提供大小,第二种形式使用dup方法创建字符串"Goodmorning"。char[9]greeting1="Hellolearnfk";char[]greeting2="Goodmorning".dup;这是使用上述简单字符数组形式的简单示例。importstd.stdio;voidm......
  • 焕颜AI DeepfaceKit 换脸变声教程
    下载安装1.软件下载地址https://exluyyho90p.feishu.cn/docx/TRBWdOfkIoFMeYxZiDZc7k62nud2.打开软件3.进入软件首页使用须知:软件集成AI实时换脸、克隆声音、背景替换、实时美颜、一键遮罩、视频图片等功能传统的Swapface、Deepface....这类软件对电脑配置要求很高,不然会非常的卡顿......
  • 无涯教程-D语言 - 条件判断
    条件判断结构包含要判断的条件以及要执行的两组语句。如果条件为true,则执行一组语句,如果条件为false,则执行另一组语句。D编程语言将任何非零和非空值假定为true,并且如果其值为零或null,则假定为false值。Sr.No.Statement&描述1ifstatementif语句由布尔表达式和一......
  • 安卓大佬力荐,送你一份超详细的Android学习教程指南
    前言之前,我们也经常听到一种声音“计算机专业已经饱和了,赚不到钱了”,但是现在,这种声音好像越来越少了,大家都没有这种担心了吗?主要是初级岗位已经趋于饱和,但高级岗位又相对缺乏,作为Android开发人员,我们应该思考怎么去往高级人才发展,而不是转学其他语言,我们是要懂得去成为金字塔顶端......
  • 无涯教程-D语言 - 循环语句
    循环语句多次执行一个语句或一组语句,以下是循环语句的一般形式,主要用于编程语言中-D编程语言提供了以下类型的循环来处理循环需求。Sr.No.LoopType&描述1whileloop当给定条件为真时,它将重复一个语句或一组语句。2forloop它多次执行一系列语句,并简化了管理循环变量......
  • 适合小白的 nvm 安装配置教程
    适合小白的nvm安装配置教程目录适合小白的nvm安装配置教程nvm简介一、nvm的安装与配置1、installnvm2、basecommand【主要验证nvm是否安装成功】3、configuretaobaomirror二、node的安装与配置1、installnode2、配置node的prefix(全局路径)和cache(缓存路径)2.1、......
  • 【Python入门教程】Python中类的用法和意义
    ​        在Python中,类是一种重要的面向对象编程概念。它们为我们提供了一种方法,可以将现实世界中的对象抽象为代码中的类,并通过类创建对象的实例。类定义了对象的结构和行为,使我们可以构建复杂的程序和数据模型。一、类的定义        在Python中,类的定义使......
  • 无涯教程-D语言 - 基本语法
    D语言非常简单易学,让我们开始创建第一个D程序!D示例让我们编写一个简单的D程序,所有D文件都将具有扩展名.d。因此,将以下源代码放入test.d文件中。importstd.stdio;/*我在D中的第一个程序*/voidmain(string[]args){writeln("test!");}假设D环境设置正确,让......