0%

Java

https://www.java.com/

Documentation

https://docs.oracle.com/en/java/javase/index.html

Changes

9-21:
https://docs.oracle.com/en/java/javase/21/language/java-language-changes.html

1.8:
https://www.oracle.com/java/technologies/javase/8-whats-new.html

1.7:
https://www.oracle.com/java/technologies/javase/7u-relnotes.html

Kotlin

https://kotlinlang.org

Documentation

https://kotlinlang.org/docs/home.html

Changes

https://kotlinlang.org/docs/whatsnew1920.html#0

Swift

https://www.swift.org

Documentation

https://www.swift.org/documentation/

Changes

https://www.swift.org/swift-evolution/
https://github.com/apple/swift/blob/main/CHANGELOG.md

Objective-C

Documentation

https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Introduction/Introduction.html#//apple_ref/doc/uid/TP40011210

https://developer.apple.com/documentation/technologies

Changes

https://developer.apple.com/library/archive/releasenotes/ObjectiveC/ModernizationObjC/AdoptingModernObjective-C/AdoptingModernObjective-C.html

C

https://en.cppreference.com/w/c

C++

https://en.cppreference.com/w/cpp

Rust

https://www.rust-lang.org

Documentation

https://www.rust-lang.org/learn

Changes

https://github.com/rust-lang/rust/blob/master/RELEASES.md

阅读全文 »

Linux

1
date -d @<timestamp>

macOS / FreeBSD

1
date -r <timestamp>

PowerShell

1
[datetime]::UnixEpoch.AddSeconds(<timestamp>)

Zsh

1
strftime '%Y-%m-%d %H:%M:%S' <timestamp>

Python

1
python3 -c "import sys, time; print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(int(sys.argv[1]))))" <timestamp>

Perl

1
perl -MPOSIX -le 'print strftime "%Y-%m-%d %H:%M:%S", localtime($ARGV[0])' <timestamp>

Ruby

1
ruby -e 'puts Time.at(ARGV[0].to_i).strftime("%Y-%m-%d %H:%M:%S")' <timestamp>

Groovy

1
groovy -e "println new Date(args[0] as long).format('yyyy-MM-dd HH:mm:ss')" <timestamp>

Node

1
node -e "console.log(new Date(parseInt(process.argv[1])).toLocaleString())" <timestamp>

存在类型(existential type), 表示某个类型存在, 设Trait A, 则some A表示存在某个类型符合A特征;
与存在类型相对应的为任意类型, any A表示负责A特征的任意类型.

设B <: A, C <: A, 则List[some A]可以是List[B]或List[C], List中元素皆为同一类型; 与之对应, List[any A]则表示该List可以存储B或C类型, List中元素不需要为同一类型.

通常, 存在类型可以编译期确定, 而任意类型需要运行期确定, 所以存在类型可以静态派发, 任意类型一般需要动态派发, 因此使用存在类型代替任意类型可以提高效率.

Rust存在类型

设有Trait A:

1
trait A {...}

Rust以impl A表示存在类型:

1
2
3
fn foo(a: impl A) {...}

fn bar(a: Vec<impl A>) {...}

这等价于

1
2
3
fn foo<T: A>(a: T) {...}

fn bar<T: A>(a: Vec<T>) {...}

Rust以dyn A表示任意类型:

1
2
3
fn foo(a: &dyn A) {...}

fn bar(a: Vec<&dyn A>) {...}

1
2
3
fn foo(a: Box<dyn A>) {...}

fn bar(a: Vec<Box<dyn A>>) {...}

由于dyn A的大小编译期未知, 所以需要使用引用, 或者使用指针例如Box.

Swift存在类型(不透明类型)

设有Protocol A:

1
protocol A {...}

Swift以不透明类型表示存在类型, 与Rust非常相似:

1
2
3
func foo(a: some A) {...}

func bar(a: Array<some A>) {...}

类似的, 这也等价于

1
2
3
func foo<T: A>(a: T) {...}

func bar<T: A>(a: Array<T>) {...}

Swift以any A表示任意类型:

1
2
3
func foo(a: any A) {...}

func bar(a: Array<any A>) {...}

C++存在类型

C++中可以使用模板表示存在类型:

1
2
3
4
5
template<typename T>
auto foo(T) -> void {...}

template<typename T>
auto bar(std::span<T>) -> void {...}

也可以加入concept约束

1
2
3
4
5
6
7
8
template<typename T>
concept A = requires(T a) {...};

template<A T>
auto foo(T) -> void {...}

template<A T>
auto bar(std::span<T>) -> void {...}

C++中任意类型和存在类型无法统一, 因为模板和concept只能用于静态约束, 任意类型需要动态约束, 可以用继承:

1
2
3
4
5
class A {...};

auto foo(A&) -> void {...} // 可以传入任意A的子类型

auto bar(std::span<A&>) -> void {...} // span中可以存储任意A的子类型引用

其中引用也可以替换为指针或者智能指针.

参考链接

https://en.wikipedia.org/wiki/Type_system#Existential_types

多态 (polymorphism) 指为不同数据类型的实体提供统一的接口, 或使用一个单一的符号来表示多个不同的类型.

子类型多态 (subtyping)

面向对象中经常提到的多态为子类型多态, 如C++的虚函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class A {
public:
virtual void f() {}
};

class B : public A {
public :
virtual void f() {}
};

int main() {
B b{};
A &a = b;
a.f();
return 0;
}

一般采用虚函数表来实现, 每个含有虚函数(包括继承得到)的类都会有一个对应的虚函数表, 存储虚函数对应指针,
编译器会为这些类型添加一个指针字段指向对应的虚函数表. 虚函数调用时, 通过该指针找到虚函数表, 再调用目标函数.

需要注意子类型并非与继承强绑定. 设类型A, B, 如果需要用到A的位置皆可由B替代, 则B是A的子类型, 即B <: A.
例如存在隐式转换int -> long, 则 int <: long; 协变情况下 List[B] <: List[A].

特设多态 (Ad hoc)

特设多态即针对同一调用不同类型有不同实现, 例如函数重载:

1
2
3
def add(a: Int, b: Int) = a + b

def add(a: String, b: String) = a ++ b

Rust中的Trait:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
trait Add {
fn add(self, rhs: Self) -> Self;
}

struct A;
struct B;

impl Add for A {...}
impl Add for B {...}

fn main {
let a = A;
let b = B;
a.add(a);
b.add(b);
}

此外, C++模板特化, C++ concept, Go interface, Swift protocol等也可表现特设多态.

参数多态 (Parametric polymorphism)

参数多态即将类型参数化, 进而做统一处理.

1
def append[T](a: List[T], b: List[T]) = a ++ b
1
def add[T: Add](a: T, b: T) = a.add(b)

静态多态与动态多态

静态多态生效于编译期, 例如C++模板, Rust静态Trait, Swift不透明类型, 静态派发的函数重载

动态多态生效于运行时, 例如虚函数, Rust动态Trait, Go interface, 动态派发的函数重载

参考资料

https://zh.wikipedia.org/zh-cn/多态_(计算机科学)

本地转发

1
2
3
4
ssh -L [bind_address:]port:host:hostport destination
ssh -L [bind_address:]port:remote_socket destination
ssh -L local_socket:host:hostport destination
ssh -L local_socket:remote_socket destination

将本地(客户端)主机上的给定 TCP 端口或 Unix Socket 转发到远程端的给定主机和端口或 Unix Socket.

例如, 服务器8080端口运行私有服务, 可以将本地8081端口转发给服务器8080端口:

1
ssh -N -L 8081:localhost:8080 user@host

即可通过访问localhost:8081来访问host:8080, 其中-N参数表示不进入交互式Shell.

假设有一内网服务器仅支持内外访问, 且没有运行ssh服务, 这时可以通过转发到另一台开启ssh服务的内网主机来访问:

1
ssh -N -L 8081:host1:8080 user@host2

即可通过访问localhost:8081来访问host1:8080, 其中host2为开启ssh服务的另一台主机.

以上命令皆省略了bind address, 默认绑定0.0.0.0, 也就是所有网络接口; 安全起见可以指明bind address明确访问范围:

1
2
3
ssh -N -L localhost:8080:host1:8080 user@host2    // 仅可通过localhost访问
ssh -N -L 192.168.1.1:8080:host1:8080 user@host2 // 监听当前内网ip, 仅可通过内网访问
...

远程转发

1
2
3
4
5
ssh -N -R [bind_address:]port:host:hostport destination
ssh -N -R [bind_address:]port:local_socket destination
ssh -N -R remote_socket:host:hostport destination
ssh -N -R remote_socket:local_socket destination
ssh -N -R [bind_address:]port destination

将远程(服务器)主机上的给定 TCP 端口或 Unix Socket 转发到本地.

假设本地8080端口运行私有服务, 将host上的8081端口转发给本地8080:

1
ssh -R 8081:localhost:8080 user@host

即可通过访问host:8081来访问localhost:8080, 这可以用来实现内网穿透.

类似地, 这里省略了bind address, 所以可以通过所以网络接口访问host该转发, 安全起见应指明bind address.

动态转发

1
ssh -N -D [bind_address:]port destination

这会启动一个SOCKS代理服务器, 例如

1
ssh -N -D 1080 user@host

启动SOCKS服务, 监听1080端口, 那么将SOCKS代理指定为localhost:1080, 会将流量转发到host, 由host发出, 例如

1
curl -x socks5://localhost:1080 https://www.google.com

该请求会被host代理.

说是新动态, 其实内容大家基本上都见过了

前言

2017 Kotlin成为Android官方支持语言

2019 Android开发Kotlin优先, 文档和库都是主要为Kotlin设计的

如今, Play商店排行前1000中, 有95%使用Kotlin (包括依赖)

70%应用本身使用Kotlin

55%使用Kotlin协程

Jetpack Compose 是完全为Kotlin设计的, 充分利用了Kotlin语言特性

Google自2019将Kotlin普遍用于Android开发, 自2022年起将Kotlin用于服务端开发

Google中数以千计的开发者编写Kotlin代码, 版本控制系统有超过1500万行Kotlin代码

Kotlin 2.0编译器 (K2编译器)

性能提升两倍

路线图

See also

https://blog.jetbrains.com/kotlin/2023/02/k2-kotlin-2-0/

https://blog.jetbrains.com/kotlin/2021/10/the-road-to-the-k2-compiler/

测试K2编译器(Kotlin1.8.20)

使用命令行参数:

-language-version 2.0

或者使用Gradle配置:

1
2
3
4
5
6
7
kotlin {
sourceSets.all {
languageSettings {
languageVersion = "2.0"
}
}
}

See also

https://kotlinlang.org/docs/whatsnew1820.html

Gradle Kotlin DSL

从Android Studio Giraffe开始, 项目模板将默认使用Gradle Kotlin DSL

和GroovyDSL相比, 得益于使用更多的静态类型, Gradle Kotlin DSL可以有更多的代码提示

并且可以通过转到定义查看更多文档

See also

https://docs.gradle.org/current/userguide/kotlin_dsl.html

Gradle版本目录(实验性功能)

使用TOML集中化管理依赖, 更加简明易维护

示例ibs.versions.toml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[versions]
com-android-application = "8.1.0-alpha11"
org-jetbrains-kotlin-android = "1.7.20"
core-ktx = "1.9.0"
junit = "4.13.2"
androidx-test-ext-junit = "1.1.3"
espresso-core = "3.4.0"
lifecycle-runtime-ktx = "2.3.1"
activity-compose = "1.5.1"
compose-bom = "2022.10.00"

[libraries]
core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" }
junit = { group = "junit", name = "junit", version.ref = "junit" }

See also

https://docs.gradle.org/current/userguide/platforms.html#sec:sharing-catalogs

https://developer.android.com/build/migrate-to-catalogs

Kotlin Symbol Processing (KSP)

kapt (Kotlin Annotation Processing Tool)

由kotlin代码生成Java stubs, 再由Java Annotation Processors处理

存在问题: 速度慢

ksp: kapt替代方案

  • 直接分析Kotlin代码
  • 速度提升两倍
  • 更好支持Kotlin特性(如可空类型)
  • 支持多平台项目

迁移到ksp

  1. 添加ksp插件
1
2
3
4
5
6
7
8
9
// 顶层声明插件版本
plugins {
id 'com.google.devtools.ksp' version '1.8.10-1.0.9' apply false
}

// 应用插件
plugins {
id 'com.google.devtools.ksp'
}
  1. 以ksp替换kapt
1
2
3
4
dependencies {
kapt 'androidx.room:room-compiler:2.5.0'
ksp 'androidx.room:room-compiler:2.5.0'
}

注意, 并非所有支持kapt的库都支持ksp, 需要库作者适配

目前支持ksp的项目: Room, Glide, Moshi, etc.

See also

https://developer.android.com/build/migrate-to-ksp

Kotlin Multiplatform (Beta)

使用Kotlin Multiplatform for Mobile(KMM)在Android和iOS中共享代码

See also

https://kotlinlang.org/docs/multiplatform-mobile-getting-started.html

一些Jetpack库开始支持Kotlin Multiplatform:

  • Annotations 1.7.0-alpha2
  • Collections 1.3.0-alpha4
  • DataStore 1.1.0-alpha3

See also

https://developer.android.com/kotlin/multiplatform?hl=zh-cn

https://android-developers.googleblog.com/2023/04/whats-new-in-jetpack-multiplatform.html

什么是Zig?

Zig is a general-purpose programming language and toolchain for maintaining robust, optimal and reusable software.

按照官网所说, Zig是一种通用编程语言和工具链, 用于维护健壮、最佳和可重用的软件.

特点

  • 无GC, 手动管理内存(支持arena等多种Allocator)
  • 强大的编译时计算能力
  • 类型可以在编译时像变量一样传递
  • 超多Targets交叉编译
  • 直接调用C语言代码和库

Hello, World

1
2
3
4
5
6
const std = @import("std");

pub fn main() !void {
const stdout = std.io.getStdOut().writer();
try stdout.print("Hello, {s}!\n", .{"world"});
}
  • 通过 @import() 导入文件, 以 @ 开头的函数为编译器内置函数
  • !voidvoidanyerror 的和类型

编译时计算

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
fn LinkedList(comptime T: type) type {
return struct {
pub const Node = struct {
prev: ?*Node,
next: ?*Node,
data: T,
};

first: ?*Node,
last: ?*Node,
len: usize,
};
}

test "linked list" {
// Functions called at compile-time are memoized. This means you can
// do this:
try expect(LinkedList(i32) == LinkedList(i32));

var list = LinkedList(i32) {
.first = null,
.last = null,
.len = 0,
};
try expect(list.len == 0);

// Since types are first class values you can instantiate the type
// by assigning it to a variable:
const ListOfInts = LinkedList(i32);
try expect(ListOfInts == LinkedList(i32));
}

调用C语言

可以通过 zig translate-c 翻译C源文件为Zig源码, 甚至可以在Zig代码中通过 @cImport 直接导入C源文件和代码, 两者原理相同.

以调用OpenSSL计算MD5为例(Zig标准库支持MD5计算: std.crypto.hash.Md5, 此处仅为演示):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const std = @import("std");
const debug = std.debug;

const ssl = @cImport({
@cInclude("openssl/ssl.h");
@cInclude("openssl/crypto.h");
@cInclude("openssl/md5.h");
}); // 导入OpenSSL头文件

fn md5sum(bytes: anytype) [ssl.MD5_DIGEST_LENGTH]u8 {
comptime debug.assert(@TypeOf(bytes[0]) == u8);
var md: [ssl.MD5_DIGEST_LENGTH]u8 = undefined;
_ = ssl.MD5(bytes, bytes.len, &md); // 调用C函数
return md;
}

build.zig 中添加链接库:

1
2
exe.linkSystemLibrary("libcrypto");  // 确保pkgconfig可以找到OpenSSL库, 此处就可以自动处理Include路径及链接库路径
exe.linkSystemLibrary("libssl");

内建Test

如同Go和Rust, Zig也内建test支持

1
2
3
test "simple test" {
try std.testing.expectEqual(2, 1 + 1);
}

run:

zig test name.zig or zig build test

内存管理

arena示例

1
2
3
4
5
6
7
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();
var map = std.StringHashMap([]const u8).init(allocator);
defer map.deinit();
try map.put("key", "value");
try testing.expect(std.mem.eql(u8, "value", map.get("key") orelse ""));

可空类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var foo: ?i32 = null;

// Coerce from child type of an optional
foo = 1234;

// Use compile-time reflection to access the child type of the optional:
comptime try expect(@typeInfo(@TypeOf(foo)).Optional.child == i32);

// Pointers cannot be null. If you want a null pointer, use the optional
// prefix `?` to make the pointer type optional.
var ptr: ?*i32 = null;

var x: i32 = 1;
ptr = &x;

try expect(ptr.?.* == 1);

// Optional pointers are the same size as normal pointers, because pointer
// value 0 is used as the null value.
try expect(@sizeOf(?*i32) == @sizeOf(*i32));

错误处理

1
2
3
4
5
6
7
8
9
10
fn failingFunction() error{Oops}!void {
return error.Oops;
}

test "returning an error" {
failingFunction() catch |err| {
try expect(err == error.Oops);
return;
};
}

交叉编译

1
$ zig targets

构建系统

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
$ zig help
Usage: zig [command] [options]

Commands:

build Build project from build.zig
init-exe Initialize a `zig build` application in the cwd
init-lib Initialize a `zig build` library in the cwd

ast-check Look for simple compile errors in any set of files
build-exe Create executable from source or object files
build-lib Create library from source or object files
build-obj Create object from source or object files
fmt Reformat Zig source into canonical form
run Create executable and run immediately
test Create and run a test build
translate-c Convert C code to Zig code

ar Use Zig as a drop-in archiver
cc Use Zig as a drop-in C compiler
c++ Use Zig as a drop-in C++ compiler
dlltool Use Zig as a drop-in dlltool.exe
lib Use Zig as a drop-in lib.exe
ranlib Use Zig as a drop-in ranlib
objcopy Use Zig as a drop-in objcopy

env Print lib path, std path, cache directory, and version
help Print this help and exit
libc Display native libc paths file or validate one
targets List available compilation targets
version Print version number and exit
zen Print Zen of Zig and exit

General Options:

-h, --help Print command-specific usage

包管理

暂时还没有

Typst是一个Rust编写的基于标记的排版系统, 正在积极开发中, 截至2023.5最新版本为0.3.0.

暂时取代LaTex不太现实, 因为各报刊杂志只会提供LaTex模板; 但是排版能力比MarkDown强太多, 可读性也比LaTex好, 而且很轻量, 只需要20MB(目前)的单二进制文件便可使用, 所以很适合处理一些轻量的排版任务.

官网: https://typst.app

GitHub: https://github.com/typst/typst

文档: https://typst.app/docs/

安装

macOS/Linux

1
brew install typst

Arch Linux

1
pacman -S typst

其他平台可参考https://github.com/typst/typst#installation

命令行使用

编译

1
typst compile file.typ

监听改动自动编译

1
typst watch file.typ

查看已安装字体

1
typst fonts

与vscode配合使用

Typst LSP插件提供了typst的lsp, 支持语法高亮和补全.

示例: 制作简历

语法很简单, 看一遍文档即可上手.

效果

代码

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#set text(
font: (
// "Source Han Serif SC", // 衬线字体, 用于打印
// "Times New Roman",
// "Songti SC",
// "STSong",
"Source Han Sans SC", // 无衬线字体, 用于显示
"Hiragino Sans GB",
"Helvetica",
),
size: 12pt,
lang: "zh",
)
#set page(
paper: "a4",
margin: (x: 1.5cm, y: 1.5cm),
footer: [
#h(1fr) #text(fill: rgb("#d9d9d9"))[powered by typst]
]
)

#set par(justify: true)

// #show heading.where(level: 2): it => text(
// weight: "medium",
// it.body,
// )

#show link: underline

#let section_line() = {
v(2pt);
line(length: 100%, stroke: 1pt + green);
v(-5pt);
}

= Alan

simpleslight\@icloud.com |
195\*\*\*\*2202 |
#link("https://github.com/suransea")[github.com/suransea] |
#link("https://shoco.top")[shoco.top]

== Summary
#section_line()

#lorem(18)

== Key Skills
#section_line()

- #lorem(7)
- #lorem(6)
- #lorem(8)
- #lorem(7)
- #lorem(6)
- #lorem(9)

== Experience
#section_line()

==== #lorem(4) #h(1fr) 2021 --

- #lorem(10)
- #lorem(18)
- #lorem(15)
- #lorem(12)
- #lorem(19)
- #lorem(13)

==== #lorem(5) #h(1fr) 2020 -- 2021

- #lorem(19)
- #lorem(15)
- #lorem(10)
- #lorem(18)
- #lorem(13)

== Education
#section_line()

#lorem(3)

#lorem(4)

2020

改变屏幕分辨率

1
adb shell wm size 1080x1920

测试不同屏幕比例适配时很有用,
可以通过

1
adb shell wm size reset

重置为默认分辨率

获取设备文字

1
adb exec-out uiautomator dump /dev/stdout

有时需要将设备上显示的一些文字复制到电脑上, 用这个命令配合grep可以快速完成

向设备输入文字

1
adb shell input text ""

向设备文本框输入文字, 可以用来传输文字到设备

查看设备代号

1
adb shell getprop | grep product

刷机时确认代号常用

查看当前活动

1
adb shell dumpsys activity activities | grep ResumedActivity

定位当前Activity

清除数据

1
adb shell pm clear com.example.app

bugreport

1
adb bugreport