仓颉编程语言青少年基础教程:输入输出

仓颉编程语言v1.0.0的输入输出由标准库的core 包(std.core)和env 包(std.env)提供。标准库的convert包(std.convert),提供了类型转换和格式化功能。

什么是“输入 / 输出”?

• 输入(Input):程序从键盘、鼠标、文件或网络读取数据。

• 输出(Output):程序把结果展示到屏幕、文件或网络。

env 包中print()、println()和readln()介绍

print()、println()和readln(),这些函数属于标准库的env 包

基本输入输出功能由标准库核心包std.core提供,该包无需显式导入,默认即可使用。其输入输出能力围绕 “控制台输出” 和 “控制台输入”。

【core 包是标准库的核心包,提供了适用仓颉语言编程最基本的一些 API 能力。

提供了内置类型(有符号整型、无符号整型、浮点型等)、常用函数(print、println、eprint 等)、常用接口(ToString、Hashable、Equatable、Collection 等)、常用类和结构体(Array、String、Range 等)、常用异常类(Error、Exception 以及它们的一些细分子类)。

core 包不需要显式导入,默认导入。写不写import std.core.*  都可以。显式写 import std.core.* 不会报错,但多余。

仓颉编程语言标准库(std)是安装仓颉 SDK 时默认自带的库。标准库预先定义了一组函数、类、结构体等,旨在提供常用的功能和工具,以便开发者能够更快速、更高效地编写程序。

标准库包含了若干包(package),而包是编译的最小单元。包可以定义子包,从而构成树形结构。

没有父包的包称为 root(根)包,root 包及其子包(包括子包的子包)构成的整棵树称为模块(module)。】

控制台输出print()和println()函数

仓颉编程语言的print()和println()输出是程序最基础的功能,其中println()会自动追加换行符。

  •  print:仅将数据的 “字符串表达” 输出到控制台,输出后光标停留在当前行末尾,后续输出会紧跟当前内容。

  •  println:在将数据 “字符串表达”输出到控制台后,自动追加一个换行符(\n),光标跳转至下一行开头。

例如:

main() {    
    println("这是println输出,自动换行")
    print("这是print输出,不自动换行。")
    print("这也是print输出。")
}

编译运行截图:

控制台输入:readln () 函数

控制台输入功能由readln()函数单独实现,用于接收用户从控制台输入的文本内容,直到遇到换行或EOF结束。

示例:(读一行)

源码如下:

import std.convert.* //使用Parse()函数用到

main() {
    // 示例1:获取用户输入并直接输出
    print("请输入你的名字:");  // 提示用户输入
    let name = readln();          // 接收用户输入的名字(字符串类型)
    println("你好,${name}!");  // 输出问候语,如输入“Bob”,则输出“你好,Bob!”

    // 示例2:获取输入并转换为其他类型(需结合类型转换API)
    print("请输入你的年龄:");
    let ageStr = readln();                // 先获取输入的字符串
    let age = Int32.parse(ageStr);        // Parse()函数,将字符串转为 Int32
    println("你的年龄是:${age}");  // 输出转换后的年龄
}

编译运行截图:

插值字符串

在仓颉编程语言中,输出语句中的 ${} 用于在字符串中内嵌表达式并进行格式化输出。语法:

${expression}

示例源码:

main() {
    // 1.基本变量插值
    let name = "仓颉"
    let version = "1.0"
    println("欢迎使用 ${name} ${version}")
    println("-------")

    // 2.表达式插值
    let a = 7
    let b = 3
    println("a + b = ${a + b}")
    println("-------")
    // 3.函数调用结果    
    func max(a: Int64, b: Int64): Int64 { if (a > b) {a} else {b}}
    let m = max(5, 9)
    println("较大值:${m}")
    println("-------")
    // 4.多行字符串中的插值
    let lang = "仓颉"
    let lines = """
    ${lang}语言
    版本 1.0
    """
    println(lines)
    println("-------")
    //5.转义与嵌套大括号
    let left = "{"
    let right = "}"
    println("转义示例:${left}内容${right}")
}

运行输出:

欢迎使用 仓颉 1.0
-------     
a + b = 10  
-------     
较大值:9   
-------     
    仓颉语言
    版本 1.0

-------
转义示例:{内容}

 

env 包的标准输入、标准输出介绍

标准库的env 包(std. env)提供当前进程的相关信息与功能、包括环境变量、命令行参数、标准流、退出程序。也提供标准输入、标准输出、标准错误进行交互的方法。

getStdIn().readln() 从标准输入中读取字符串。

getStdIn().read() 从标准输入中读取一个字符。

getStdOut().write() 从标准输出中输出字符串,不自动换行。

getStdOut().writeln() 从标准输出中输出字符串,并自动换行。

【错误流通常也支持类似write()/writeln()的方法(用于输出错误信息)。

getStdErr()  获取当前进程标准错误流。

getStdIn()           获取当前进程标准输入流。

getStdOut()  获取当前进程标准输出流。

补充说明

• 标准输入(stdin):键盘 → 程序
• 标准输出(stdout):程序 → 屏幕
• 标准错误(stderr):程序 → 屏幕(专门报错)

标准输入,接收外部输入数据的默认来源,通常是键盘(用户通过键盘输入内容)。

标准输出,输出正常结果的默认目的地,通常是控制台(终端窗口),用户可以直接看到输出内容。

标准错误,输出错误信息的专用数据流,通常也是控制台(和 标准输出 看起来一样),但逻辑上是独立的流,输出错误、警告、诊断信息。

本包提供多平台统一操控能力,目前支持 Linux 平台,macOS 平台,Windows 平台与 HarmonyOS 平台。】

下面给出示例。

字符串级读(读一行)

方式1:使用readln()

readln()能从标准输入中读取字符串,示例见前面。

import 语句导入其它包中的声明或定义】

方式2:使用getStdIn().readln()  ,功能类似std.core的readln()

需要使用 import —— import std.env.*

源码如下:

字符串级读(读一行)

方式1:使用readln()

readln()能从标准输入中读取字符串,示例见前面。

import 语句导入其它包中的声明或定义】

方式2:使用getStdIn().readln()  ,功能类似std.core的readln()

需要使用 import —— import std.env.*

源码如下:

import std.env.*

main() {
    getStdOut().write("请输入:")          // 可换 print("请输入:")
    var line = getStdIn().readln()     // 读取字符串
    var r = line.getOrThrow()           // 拆包
    getStdOut().writeln("你输入的是:${r}")  // 可换 println("你输入的是:${line}")
}

说明:其中两行

    var line = getStdIn().readln()     // 读取字符串

    var r = line.getOrThrow()           // 拆包

可写为一行

var line = getStdIn().readln().getOrThrow()  //读取字符串, 并拆包

编译运行截图:

字符级读

可以用getStdIn().read()读取一个字符。示例源码如下:

import std.env.*

main() {  
    print("请输入字符:")   
    let c = getStdIn().read().getOrThrow()  // 读取一个字符,并拆包
    println("你输入的字符是: ${c}")
    getStdOut().writeln("你输入的字符是: ${c}")
}

编译运行

请输入字符:中国
你输入的字符是: 中
你输入的字符是: 中

字节级别(二进制场景)读

示例源码如下

import std.env.*

main() {
    let buf: Array<UInt8> = [0, 0, 0, 0]  // 创建一个长度为4的UInt8数组(可容纳4个字节)
    print("请输入:") 
    let n = getStdIn().read(buf) // 从标准输入读取字节,存入buf
    println("读到 ${n} 字节:${buf[..n]}") //输出字节值
    
    // 遍历打印读取到的字节值
    for (i in 0..n) {
        print("${buf[i]} ")
    }
}

编译运行

请输入:中华人民共和国
读到 4 字节:[228, 184, 173, 229]
228 184 173 229

说明:

1.缓冲区大小

buf 只有 4 个 UInt8,所以 getStdIn().read(buf) 最多读 4 个字节。

2.汉字 UTF-8 长度

“中”的 UTF-8 编码:E4 B8 AD → 3 字节

“华”的 UTF-8 编码:E5 8D 8E → 3 字节

3.字节只能装下 E4 B8 AD E5,于是你看到数组里恰好是

[0xE4, 0xB8, 0xAD, 0xE5] → 十进制 [228, 184, 173, 229]

4.后续字节仍在输入缓冲区

剩下的 8D 8E ... 还留在系统输入队列中;下次再读就能拿到。

convert包的常用功能介绍

标准库的convert包(std.convert)提供了强大的类型转换和格式化功能

  •  类型转换:支持将字符串解析为特定类型,也支持将其他类型转换为字符串。如其中Parsable<T>接口提供常规转换parse和tryParse函数。

  •  格式化输出:格式化format函数功能,可将数据类型转换为指定格式的字符串(如控制宽度、对齐方式、进制、小数精度等)。

类型转换

parse函数和tryParse函数的区别

  •  parse 转换失败 直接抛异常,程序会当场崩溃(IllegalArgumentException)。

  •  tryParse 转换失败 不抛异常,而是返回一个 Option(选项) 包裹的结果:

        – 成功 → Some(值)

        – 失败 → None

示例 1:使用parse函数常规转换,可以使用try-catch处理已知可能异常的情况:

import std.convert.*

main() {
    // 1. Bool转换
    let boolVal = Bool.parse("true");
    println("Bool转换结果:${boolVal}"); // 输出:true

    // 2. Int32转换(带负号)
    let intVal = Int32.parse("-456");
    println("Int32转换结果:${intVal}"); // 输出:-456

    // 3. Float64转换(科学计数法)
    let floatVal = Float64.parse("3.14e2");
    println("Float64转换结果:${floatVal}"); // 输出:314.0

    // 以下代码会抛IllegalArgumentException(演示异常场景)
    // let invalidInt = Int32.parse("123a"); // 含非数字字符
    // let overflowInt = Int8.parse("128"); // 超出Int8范围(127)
}

示例 2:使用tryParse函数,需通过 “模式匹配” 或 “判空” 处理结果,适合不确定输入是否合法的场景:

import std.convert.*;

main(){
    /* 例 1:Int32 失败 */
    let maybeInt = Int32.tryParse("abc")
    match (maybeInt) {
        case Some(v) => println("Int32 成功:${v}")
        case None    => println("Int32 失败:不是整数")
    }

    /* 例 2:UInt8 成功 */
    let maybeUint = UInt8.tryParse("255")
    match (maybeUint) {
        case Some(u) => println("UInt8 成功:${u}")
        case None    => println("UInt8 失败")
    }

    /* 例 3:Rune 失败(长度≠1)*/
    let maybeRune = Rune.tryParse("AB")
    if (maybeRune.isNone()) {
        println("Rune 失败:长度不为 1")
    }
}

示例3,输入一个数,判断它的奇偶性:

import std.convert.*
main() {
    print("请输入一个整数:")
    var str: String  = readln()
    var n =  Int64.parse(str)
    
    // 判断奇偶
    if (n % 2 == 0) {
        println("${n} 是偶数")
    } else {
        println("${n} 是奇数")
    }
}

或写为:

import std.env.*
import std.convert.*
main() {
    getStdOut().write("请输入一个整数:")          // 可换 print("请输入一个整数:")
    var str: String  = getStdIn().readln().getOrThrow()  //读取字符串, 并拆包
    var n =  Int64.parse(str)
    
    // 判断奇偶
    if (n % 2 == 0) {
        println("${n} 是偶数")
    } else {
        println("${n} 是奇数")
    }
}

format函数格式化功能

尽管 format函数 支持 “实例.点语法” 这种类似方法的调用方式,但核心依据官方接口的 static func 声明,以及 “语法糖不改变本质” 的原则,其规范名称仍是 “函数”(更具体地说,是 “静态函数”)。

基本调用格式

value.format(format_spec)

其中:

  •  value:要格式化的值(任何实现了Formattable接口的类型)

  •  format_spec:格式说明符字符串,遵循特定语法:[flags][width][.precision][specifier]

format_spec(格式说明符)部分的说明:

1. flags(标志位)

用于控制对齐方式、符号显示、进制前缀等,支持 4 种标志:

标志

适用类型

功能说明

-

Int、UInt、Rune、Float

左对齐,空位补在右侧(默认右对齐)。

+

Int、UInt、Float

正数强制显示+号,负数仍显示-号。

#

Int、UInt(进制转换时)

为进制格式添加前缀:二进制(0b/0B)、八进制(0o/0O)、十六进制(0x/0X)。

0

Int、UInt、Float

空位用0填充(而非默认空格)。

示例

import std.convert.*

main() {
    var num: Int32 = 20;
    
    // 左对齐(宽度10)
    print("\"${num.format("-10")}\"\n");  // 输出:"20        "
    
    // 强制显示正号(宽度10,右对齐)
    print("\"${num.format("+10")}\"\n");  // 输出:"       +20"
    
    // 十六进制加前缀(宽度10)
    print("\"${num.format("#10x")}\"\n"); // 输出:"       0x14"
    
    // 0填充(宽度10)
    print("\"${num.format("010")}\"\n");  // 输出:"0000000020"
}

2. width(宽度)

指定输出字符串的最小宽度(正整数),若实际内容长度小于宽度,则用空格(或0,若指定0标志)填充;如果实际值宽度大于指定宽度,不会截断:

  •  无符号:默认右对齐,空位补在左侧。

  •  带-:左对齐,空位补在右侧。

  •  若内容长度超过宽度,不截断,按实际长度输出。

  •  符号(+/-)和进制前缀(如0x)会占用宽度计数。

示例:

import std.convert.*

main() {
    var num: Int32 = 20;
    
    // 宽度1(小于实际长度2,不截断)
    println("\"${num.format("1")}\"");  // 输出:"20"
    
    // 宽度4,带正号(+占用1个字符位)
    println("\"${num.format("+4")}\""); // 输出:" +20"
}

3. precision(精度)

以.开头的正整数,对整数和浮点数的影响不同,对于浮点数:指定小数位数;对于整数:指定最小数字位数(不足时用前导零填充):

类型

功能说明

浮点数

控制小数点后有效数字的位数:
- 不足则补位(不一定补 0);
- 超过则四舍五入;
- 未指定时默认保留 6 位小数。

整数

控制最小位数:
- 不足则在前面补0;
- 超过则无效果。

示例:

import std.convert.*

main() {
    var f: Float64 = -1234.123456;
    
    // 浮点数:精度4(保留4位小数)
    println("\"${f.format(".4")}\"");  // 输出:"-1234.1235"
    
    // 浮点数:精度20(保留20位小数)
    println("\"${f.format(".20")}\"");  // 输出:"-1234.12345600000003287278"
}

4. specifier(格式符)

指定数据的输出格式(如进制、科学计数法等),不同类型支持的格式符不同:

格式符

适用类型

功能说明

b/B

Int、UInt

二进制格式输出(b小写,B大写,仅影响进制前缀,如0b/0B)。

o/O

Int、UInt

八进制格式输出(o对应0o前缀,O对应0O前缀)。

x/X

Int、UInt

十六进制格式输出(x对应0x前缀,X对应0x前缀,字母部分x小写、X大写)。

e/E

Float

科学计数法输出(e对应小写e,E对应大写E)。

g/G

Float

自动选择精简格式(十进制或科学计数法,优先更短的表示)。

示例:

import std.convert.*

main() {
    // 整数进制转换
    var num: Int32 = 20;
    println("二进制: ${num.format("b")}");    // 输出:"10100"
    println("八进制: ${num.format("o")}");    // 输出:"24"
    println("十六进制: ${num.format("x")}");  // 输出:"14"
    println("带前缀十六进制: ${num.format("#X")}");  // 输出:"0X14"
    
    // 浮点数格式
    var f: Float32 = 1234.1;
    var largeF: Float32 = 123412341234.1;
    println("科学计数法: ${f.format("20.2e")}");  // 输出:"            1.23e+03"
    println("精简格式: ${largeF.format("20G")}");  // 输出:"         1.23412E+11"
}

最后,给出一个format函数综合示例:

import std.convert.*

main() {
    // 整数格式化示例
    let num = 12345
    
    // 基本格式化
    println(num.format(""))          // 默认格式: "12345"
    println(num.format("10"))      // 宽度10,右对齐: "     12345"
    println(num.format("-10"))     // 宽度10,左对齐: "12345     "
    println(num.format("010"))     // 宽度10,零填充: "0000012345"
    println(num.format("+10"))     // 显示正号: "    +12345"
    
    // 进制格式化
    println(num.format("b"))       // 二进制: "11000000111001"
    println(num.format("o"))       // 八进制: "30071"
    println(num.format("x"))       // 十六进制(小写x): "3039"
    println(num.format("X"))       // 十六进制(大写X): "3039"
    println(num.format("#x"))      // 带前缀十六进制: "0x3039"
    
    // 浮点数格式化示例
    let pi = 3.1415926535
    
    // 小数精度控制
    println(pi.format(""))           // 默认: "3.141593"
    println(pi.format(".2"))       // 2位小数: "3.14"
    println(pi.format(".5"))       // 5位小数: "3.14159"
    
    // 科学计数法
    println(pi.format(".3e"))      // 科学计数法,3位小数: "3.142e+00"
    println(pi.format(".3E"))      // 科学计数法(大写),3位小数: "3.142E+00"
    
    // 通用格式
    println(pi.format(".3g"))      // 通用格式,3位有效数字: "3.14"
    
    // 组合使用
    println(pi.format("-10.2e"))   // 左对齐,宽度10,科学计数法: "3.14e+00  "     
}

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐