Go fmt包

fmt包提供了格式化输入、输出的功能。 格式化输出 函数名 说明 Print 以默认格式进行格式化,格式化结果输出到os.Stdout Printf 以指定格式进行格式化,格式化结果输出到os.Stdout Println 以默认格式进行格式化,并在末尾添加换行符,格式化结果输出到os.Stdout Fprint 以默认格式进行格式化,格式化结果输出到指定的io.Writer接口 Fprintf 以指定格式进行格式化,格式化结果输出到指定的io.Writer接口 Fprintln 以默认格式进行格式化,并在末尾添加换行符,格式化结果输出到指定的io.Writer接口 Sprint 以默认格式进行格式化,格式化结果以字符串形式返回 Sprintf 以指定格式进行格式化,格式化结果以字符串形式返回 Sprintln 以默认格式进行格式化,并在末尾添加换行符,格式化结果以字符串形式返回 具体格式化规则详见Go 格式化。 格式化输入 函数名 说明 Scan 按默认格式从os.Stdin进行扫描,空格用于分隔数据,换行符按空格处理,扫描结果存入对应的变量 Scanf 按指定格式从os.Stdin进行扫描,扫描结果存入对应的变量 Scanln 按默认格式从os.Stdin进行扫描,空格用于分隔数据,遇换行符时停止扫描,扫描结果存入对应的变量 Fscan 按默认格式从指定的io.Reader接口进行扫描,空格用于分隔数据,换行符按空格处理,扫描结果存入对应的变量 Fscanf 按指定格式从指定的io.Reader接口进行扫描,扫描结果存入对应的变量 Fscanln 按默认格式从指定的io.Reader接口进行扫描,空格用于分隔数据,遇换行符时停止扫描,扫描结果存入对应的变量 Sscan 按默认格式从指定的字符串中进行扫描,空格用于分隔数据,换行符按空格处理,扫描结果存入对应的变量 Sscanf 按指定格式从指定的字符串中进行扫描,扫描结果存入对应的变量 Sscanln 按默认格式从指定的字符串中进行扫描,空格用于分隔数据,遇换行符时停止扫描,扫描结果存入对应的变量 注意:变量前必须要带上&才能成功接收扫描到的数据! 其它 函数名 说明 Append 以默认格式进行格式化,格式化结果追加到指定的字节切片,并返回新的字节切片 Appendf 以指定格式进行格式化,格式化结果追加到指定的字节切片,并返回新的字节切片 Appendln 以默认格式进行格式化,并在末尾添加换行符,格式化结果追加到指定的字节切片,并返回新的字节切片 Errorf 以指定格式进行格式化,格式化结果转为error接口并返回

2024-10-16 20:51:40 · 1 分钟 · 慢步道人

Go 格式化

格式化动词 常规 格式化动词 含义 %v 默认格式 %T 数据的类型 %% %本身 使用%v时不同类型默认对应的格式化动词如下: 数据类型 格式化动词 说明 bool %t int int8 等 %d uint uint8 等 %d %#v时对应%#x float32 complex64 等 %g string %s chan %p pointer %p 布尔型 格式化动词 含义 示例 结果 %t true或false 1>2 false 整型 格式化动词 含义 示例 结果 %b 二进制 90 1011010 %c 对应的 Unicode 字符 90 Z %d 十进制 90 90 %o 八进制 90 132 %O 带0o前缀的八进制 90 0o132 %q 用单引号包括的对应的 Unicode 字符,并且特殊字符会进行转义 90 ‘Z’ %x 小写的十六进制 90 5a %X 大写的十六进制 90 5A %U Unicode 格式:U+1234;与U+%04X相同 90 U+005A 浮点型和复数型 格式化动词 含义 示例 结果 %b 十进制无小数的科学计数法表示浮点数,指数部分是2的幂次方 3....

2024-10-15 21:34:07 · 2 分钟 · 慢步道人

Lazarus获取纳秒级时间

背景 最近在改写一个加密算法,算法不可避免用到了随机数,但是Lazarus默认的随机种子初始化函数Randomize是依赖于GetTickCount的,而GetTickCount的时间精度是毫秒级的(windows平台实际大约是16ms级),日常是够用的,但在加密算法中就显得太过粗糙了。 关于GetTickCount的时间精度,详见Delphi中的延时和在Lazarus中分析Windows和Linux的延时。 在以上文章中有提到,windows平台下可以使用QueryPerformanceFrequency和QueryPerformanceCounter获取高精度的时间,事实上是微秒级的时间(本机实测是0.1微秒级,即百纳秒)。 考虑跨平台的话,如何获取非windows平台的高精度时间就变得很有必要了。 解决方案 搜索资料及查看Lazarus源码,找到了fpgettimeofday和clock_gettime两个函数。 fpgettimeofday fpgettimeofday实际上就是UNIX平台的gettimeofday,只引用unix单元即可。其定义如下: 1 function fpgettimeofday(tp: ptimeval;tzp:ptimezone):cint; external name 'FPC_SYSC_GETTIMEOFDAY'; 其参数ptimeval的定义如下: 1 2 3 4 5 6 7 8 9 10 timeval = record tv_sec:time_t; {$ifdef CPUSPARC64} tv_usec:cint; {$else CPUSPARC64} tv_usec:clong; {$endif CPUSPARC64} end; ptimeval = ^timeval; TTimeVal = timeval; 另外,unix平台的GetTickCount64用到了fpgettimeofday: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function GetTickCount64: QWord; var tp: TTimeVal; {$IFDEF HAVECLOCKGETTIME} ts: TTimeSpec; {$ENDIF} begin {$IFDEF HAVECLOCKGETTIME} if clock_gettime(CLOCK_MONOTONIC, @ts)=0 then begin Result := (Int64(ts....

2024-08-31 21:25:25 · 2 分钟 · 慢步道人

Lazarus跨平台方案总结

前言 对于Lazarus跨平台开发接触有一段时间了,虽然踩了不坑,但仍觉得已踩过的坑不过是九牛一毛。不过还是应该记录一下,以备忘,以后又踩新坑了再补充吧。 环境 项目 Linux Windows 操作系统 Debian 12 Win10 CPU架构 x86_64 x86_64 桌面环境 xfce 4 / 输入法 fcitx 5 系统自带 GUI环境 gtk2/qt5/qt6 win32/gtk2/qt5 目标程序 64位 32位/64位 Qt6Pas1.dll未能得到,win + qt6未测试 linux 64位系统未能设置好32位运行环境,未测试 qt5未能得到64位的dll,未测试 坑 windows Application.MessageBox按钮文字英文,无法直接本地化,Windows.MessageBoxAPI可以 TPageControl组件自带的关闭按钮在win32下不可用,gtk2和qt5正常 qt5下,某些组件会有很诡异的现象 gtk2下,64位目标程序运行时报错 gtk2下,默认界面很丑,需要用皮肤 带GUI的dll机制和行为与delphi不一致 使用ShareMem单元需要自行构建fpcmemdll.dll linux gtk2版IDE无法输入中文;目标程序可正常输入(SynEdit不可以,必须修改相关源码) qt5和qt6版IDE可输入中文,但部分字无法输入,也无法正常输入多于两个字的词组;目标程序存在相同的问题 qt5版IDE及目标程序所需要的libqt5pas一定要和编译用的IDE版本匹配 总结 基于有限的测试经验,得出了以下结论: 虽然Lazarus是跨平台的,并且号称一次编写,到处编译,但GUI的跨平台表现是不完全一致的,需要分别处理 整体上,gtk2兼容性和稳定性优于qt 最佳的开发方案:在windows系统上开发,然后交叉编译或在目标环境下进行编译(若使用了SynEdit,必须修改相关源码) 保持跨平台一致性的方案:windows平台采用32位的gtk2+皮肤,linux平台采用gtk2+皮肤

2024-08-07 21:57:25 · 1 分钟 · 慢步道人

在Lazarus中分析Windows和Linux的延时

前言 之前用Delphi时,研究过延时及其时间精度,并写了篇文章——Delphi中的延时,当时是仅在windows平台下测试的,现在想用Lazarus分别在windows和linux平台测试对比下。 测试 测试环境 CPU:x86_64 win:win10 linux:debian 12.6 + xfce ide:Lazarus 3.4 + fpc 3.2.2 测试设计 整体与之前的设计保持一致,增加了GetTickCount64的测试,Timer的测试有改动,具体如下: 假定系统时间是足够精确的,因此使用Now分别在延时前后获取系统当前时间来进行耗时评估。 为使测试更具代表性,每个测试点连续测试100次,取算术平均值。 在1ms~100ms内,测试点步长为1ms,在100ms~1000ms内,测试点步长为10ms。 为尽可能减小干扰,测试过程中未使用并行,Sleep、GetTickCount和GetTickCount64未使用Application.ProcessMessages;,Timer绕不开事件触发,使用了Application.ProcessMessages;。 测试结果 windows 延时(ms) Sleep GetTickCount GetTickCount64 Timer 1 1.93 15.51 15.63 15.62 2 2.93 16.59 15.62 15.63 3 3.95 15.58 15.62 15.66 4 5.10 15.49 15.94 15.61 5 5.86 15.55 15.62 15.65 6 6.83 15.50 15.62 15.63 7 7.81 15.62 15.63 15.67 8 8.77 15.55 15.63 15.68 9 9.76 15....

2024-07-24 23:23:07 · 10 分钟 · 慢步道人

在Lazarus中使用ShareMem

问题 使用Delphi开发应用时,如果要在主程序和dll间传递字符串、对象等不兼容C的类型时,通常需要在主程序和dll工程的uses区第一个位置引用ShareMem单元,并将borlndmm.dll随应用一起发布使用。 Lazarus中也有ShareMem单元,说明也可以采用相同的策略解决同样的需求,但是并不是使用borlndmm.dll。 在源码sharemem.pp中可以看到const fpcmemdll = 'fpcmemdll.dll';,说明使用的是fpcmemdll.dll,但是这个dll实际上是并不存在的! 解决 全盘搜索并没有找到fpcmemdll.dll,但是却找到了fpcmemdll.pp。 打开fpcmemdll.pp后发现,其实这并不是一个普通的用于uses的单元,而是一个library工程单元,那么问题就好办了。 创建一个空白library工程,并命名为fpcmemdll 复制fpcmemdll.pp内容到fpcmemdll.lpr 构建fpcmemdll.lpr得到fpcmemdll.dll 其它 linux平台似乎并没有ShareMem单元,也不存在以上用法,应该是只有windows平台才要这样用。

2024-07-23 20:40:36 · 1 分钟 · 慢步道人

让应用以单例运行

从其它平台迁移而来 有时候我们会期望所编写的应用只运行一个实例,比如监听网络端口或串口,用Lazarus有两种不同的实现方案。 SingleInstanceEnabled属性 SingleInstanceEnabled是TCustomApplication的属性,在初始化之前设置为True即可轻松实现单实例应用: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 program project1; {$mode objfpc}{$H+} uses AdvancedSingleInstance, //注意:必须引用该单元!!! Interfaces, Forms, ...; {$R *.res} begin Application.SingleInstanceEnabled := True; //注意:必须在调用 Initialize 前赋值!!! Application.Initialize; ... Application.Run; end. 特别注意 必须引用AdvancedSingleInstance单元,且该单元必须在Interfaces单元和Forms单元前 必须在调用Application.Initialize前赋值 该方法仅针对同一个可执行文件生效,并非系统全局生效 互斥对象 利用操作系统的互斥对象可实现系统级的单例。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var AppMutex: THandle; begin Application....

2024-01-26 22:24:01 · 1 分钟 · 慢步道人

给json数组中的元素排序

从其它平台迁移而来 起因 基本信息 平台:windows IDE:Lazarus 2.2.6 json包:FPC自带的fpjson 背景 最近在搞一个小工具,数据文件采用的是json格式,其中一个节点存放的是一组文件的基本信息的清单,这个节点自然就是个json数组,元素就是每个文件基本信息的json对象。界面展示用的是经典的DBGrid + DataSource + DataSet方案,所以会把json数组转为DataSet。 操作过程中会比对磁盘上的文件,该添的添,该删的的删,该改的改,该标记的标记。一番操作下来,顺序自然是乱的,虽然可以操作DataSet或者换用带排序功能的DBGridEh达到排序的目的,但直接看json数据的话,依然是乱序的。因此,期望直接对json数组进行排序。 解决过程 习惯先看源码,如果没有原生解决方案了,或者原生解决方案太别扭了,才会选择第三方解决方案或自己造轮子。 一看源码 1 2 3 4 TJSONArray = class(TJSONData) public ... Procedure Sort(Compare: TListSortCompare); TJSONArray已经提供了排序方法,不过这个参数是什么东西? 1 TListSortCompare = function (Item1, Item2: Pointer): Integer; 嗯,是个函数声明,也就是说具体的算法实现要自己写,可以先找找看有默认的实现没。结果是:没有!那就自己写吧。 看声明,这个函数是要比较两个指针指向的东西,并返回一个整数。嗯,看上去很简单,不过: 到底是怎么实现排序的? 参数是指针,指向的又是什么东西? 返回一个什么样的整数才能实现排序呢? 没懂!!! 还是接着看源码吧: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 procedure TJSONArray....

2023-11-28 21:38:45 · 3 分钟 · 慢步道人

给类型、记录、类添加助手

从其它平台迁移而来 通常情况下,类型和记录是没有方法的,只有类有方法,但是可以通过给类型和记录添加助手来达到类似于类的方法的功能,当然,也可以给类添加助手。 语法 1 2 3 HelperName = class|record|type helper[(OptionalBaseHelper)] for TypeName [properties, procedures, functions, constructors, consts, vars] end [hint modifiers]; 类助手 FPC 2.6+版本可用,ObjFPC模式下无需特别设置。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 //定义 TObjectHelper = class helper for TObject function SomeFunc: string; end; //实现 function TObjectHelper.SomeFunc: string; begin Result := '类名:' + Self.ClassName; end; //使用 var o: TObject; begin Writeln(o.SomeFunc); end. 一般情况下,给类添加方法可直接在类中添加,但这样添加的方法会直接在所有后代类中显示,如果只是想在特定的范围内添加方法,就可以使用类助手。...

2023-08-25 20:38:35 · 1 分钟 · 慢步道人

使用Lazarus压缩/解压zip

从其它平台迁移而来 Lazarus默认已经提供了zip文件的压缩和解压功能,在Zipper单元中,不过,使用过程中还是有一些细节需要注意。 压缩 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 uses Zipper; { 使用类方法进行压缩 } //压缩单个文件 TZipper.Zip('压缩后的文件.zip', '待压缩的文件.txt'); //压缩多个文件 TZipper.Zip('压缩后的文件.zip', ['待压缩的文件1.txt', '待压缩的文件2.pdf']); { 使用实例对象进行压缩 } var zip: TZipper; zip := TZipper.Create; try //压缩单个文件 zip.ZipFile('压缩后的文件.zip', '待压缩的文件.txt'); //压缩多个文件 zip.ZipFiles('压缩后的文件.zip', ['待压缩的文件1.txt', '待压缩的文件2.pdf']); finally zip.Free; end; 以上为比较方便的使用方法,但是还存在一些问题: 以上仅限于文件名为英文的情况,若文件名为中文则会出现乱码(主要是在windows平台上,用专门的压缩/解压工具打开查看列表和解压时)。查看解决方案。 若待压缩的文件包括路径,则压缩后的文件内也会包含传参时传入的路径。查看解决方案。 另外,也可以配合FileName(压缩后的文件名)和Entries(待压缩的文件)属性使用ZipAllFiles方法;或者配合Entries(待压缩的文件)属性使用SaveToFile方法。不过,多次调用前一定要调用Clear方法,否则就会受前一次压缩操作的影响。 解压 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 uses Zipper; { 使用类方法进行解压 } //解压出全部文件 TUnZipper....

2023-07-29 21:31:15 · 1 分钟 · 慢步道人