duangsuse::Echo
719 subscribers
4.28K photos
130 videos
583 files
6.49K links
import this:
美而不丑、明而不暗、短而不凡、长而不乱,扁平不宽,读而后码,行之天下,勿托地上天国。
异常勿吞,难过勿过,叹一真理。效率是很重要,盲目最是低效。
简明是可靠的先验,不是可靠的祭品。
知其变,守其恒,为天下式;穷其变,知不穷,得地上势。知变守恒却穷变知新,我认真理,我不认真。

技术相干订阅~
另外有 throws 闲杂频道 @dsuset
转载频道 @dsusep
极小可能会有批评zf的消息 如有不适可退出
suse小站(面向运气编程): https://WOJS.org/#/
Download Telegram
dnaugsuz
基本满意,可是我真的很想给这些 Annotation 弄成 alllower 的…… 我讨厌无论实际语义如何都用『统一』的代码风格
居然连 @Builder 都有了,我瞬间有一种官方逼死同人的感觉,本来我也想写的…… 😿 看来意义降低一半了
Forwarded from dnaugsuz
是的,场景、能用是关键,所以代码质量不重要、抽提逻辑也不重要,个人有的强迫症也不重要,满足需求就足够了,任何可复用的库,都应该是满足需求的,这点很正确。

只有最终实现了才行,实现最重要,所以才有你看到那么多发布了 11 个版本还是一样复杂的库,真的是它们已经无从简化?其实是它们已经满足了需求和自己的场景,站稳了自己的位置,当然不需要『最大化』某些东西了。作者看得懂就够了。
当然不需要再写第二遍了,当然不需要 Literate Programming 了,因为他们能用了嘛、IP(Intelligence Property)。
是的,第二遍不重要,只有傻逼才会写第二遍、只有傻逼才会慢慢按层次把一个个 interface 划分开来、只有傻逼才会对一些诸如最终 .class 体积之类的问题死缠烂打(其实我也没死揪),大家都是那样的,把 isEmpty, containsKey, containsValue, entrySet 什么的一股脑塞到某一个地方去,脑容量大一点的人不再乎。
Java 也是这样的,不过 Kotlin 不是这样的,我甚至没听说过 Kotlin 可以把 interface 里放上 default 实现。

实现了就好嘛,也不需要再三思考自己到底写的是为了什么、不需要再三重新审视自己的需求、数据的依赖、生存周期、可变性、最终的目标算法、编程技巧,到底最终的『需求』是什么,最后写出一大堆所谓的设计模式出来,然后不是设计模式的都写得像脚本或者汇编、Shell 一般,其实到底最终还是没有抓住关键问题在哪里。

我是个很垃圾的工程师,也见过很牛逼的工程师写的程序,他们很厉害,他们重视面向对象设计模式、可复用、可组合(比如,XMLPull 的 Data Event 模式)、可配置(比方说,一切皆 XML)、测试、部署、DevOps,甚至还有一群人成天把什么『Presentation』『case study』挂在嘴边 — 就是那些所谓的『Agile Development』者啦。

是,这个问题对我重要,因为我其实也觉得 class file 的体积,那一点代码和 term 不算什么,只是我之前老毛病犯了,忍不住想把最终代码弄小点,我明白它没有意义,但被『所有人』忽视的点里,难道就没有应该重视的东西?难道『堆砌』代码而不是做『设计』的只有我一个?

当然,不少人不仅仅不会觉得输出 java class 代码的体积算得了什么,慢慢地连自己编写给自己看的代码体积也不算什么了,你看 — 它不是满足需求了么?它通过测试了不是么?它在 JDK 里面了不是么?
回到我们的初心,后来才发现,其实『写好代码』和『做完工作』,它们根本不冲突。

并且,好的程序员就应该把『写好代码』作为自己的最低标准。
我想死的心都有了,看来 @in @out 依然可以实现,不过要这样!作为一个 checker……
『讷,这就是核心部分的代码了,没有问题我去睡觉了』
rangemap.zip
25.1 KB
第二版,更好更简单
duangsuse::Echo
『讷,这就是核心部分的代码了,没有问题我去睡觉了』
哦,对了,不得不说一下 RangeMap 到底是怎么工作的
其实 RangeMap 本来应该是 template<> RangeMap<int, int>, 反正它的真名是 RayRangeMap,利用数学的『射线』进行建模优化的算法,也就利用 Comparable 泛化了一下……

val rm = RangeMap<Int, String>()
rm[0 until 1] = "0"
rm[1 until 4] = "123"
rm[4 until 6] = "45"

assert (0 in rm)
assert (3 in rm)
assert (rm.containsEdge(0))
assert (6 !in rm)
assert (rm[0] == "0")
assert (rm[3] == "123")
assert (rm[5] == "45")
assert (rm.containsShadow(5))

理论上,RangeMap 只需要 O(log2 n) 的复杂度即可查找到某一个项目,并且比 HashMap 节省空间。
RangeMap 是一个在有序的序列存储后端上执行二分查找的算法,所以可以达到这样的时间/空间复杂度
(其实本身不是特别复杂,不过作为一个类封装起来会好用很多)
rangemap.kra
649.4 KB
rangemap.png
113.6 KB
class Array
def lookupFirstGE(near, beg = 0, endInclusive = size-1)
puts("#{beg} until #{endInclusive}")
viewport = endInclusive - beg
if viewport == 0 then return self[beg] end
if viewport == 1 then return self[endInclusive] end
mid = (viewport+1) / 2; item = self[mid]
return case
when item == near then item
when item > near then lookupFirstGE(near, beg, mid-1)
when item < near then lookupFirstGE(near, mid+1, endInclusive)
end
end
end

写不出 算了
duangsuse::Echo
class Array def lookupFirstGE(near, beg = 0, endInclusive = size-1) puts("#{beg} until #{endInclusive}") viewport = endInclusive - beg if viewport == 0 then return self[beg] end if viewport == 1 then return self[endInclusive] end mid = (viewport+1)…
说实话,今天我都有点不想写 RangeMap 了,毕竟昨天因为害怕写不完的缘故,我凌晨两点才睡觉…… 彼时我喉咙还有点发炎,现在是非常发炎
(而且那一部分核心代码应该是必须得重写了,我没考虑到不能向下圆整的问题,我也不确定 (a+1)/b 是否就是向上圆整了)
duangsuse::Echo
『讷,这就是核心部分的代码了,没有问题我去睡觉了』
我打算用循环写,毕竟循环更灵活,可以解决 floor div 导致的代码繁复问题,也不会陷入死循环(因为我不需要给 GT 的情况『留空』了,我只需记录最后 GT 的索引即可)
不写了、放弃了、累死了,这 Annotation Processor 是多麻烦,一个 AST 想解构还不容易啊…… 如果用 Visitor pattern 会方便很多,可我需要能够检查 path 的 Tree/Visitor,不知道有没有这种 API,这次只能暂时以二分查找最小的 (it >=k) 结尾吧,写点其他的吧…… #task
我还用 Resource Bundle,resources 简直就一大坑,我不该一上来就用 resources 的! #Java
或许我下次应该找一个大佬分享一下写 APT 的技巧,比如说,@NamePrefix("pref") class 怎么要求里面的 executable, filed, localvar 啊都拿这个做前缀…… 比如 @hasGetter @hasProtectedSetter @data 怎么实现……
我真的不想光写一个那啥,但是不用 Visitor 和对象内部状态解决那个树的访问问题实在太过分了,可有些东西我不知道该怎么办啊…… 一些东西容易混淆,比如 Class 的 type param list 和 TypeParameter…… 语法上是一样的
rangemap_1.zip
45.5 KB
duangsuse::Echo
不写了、放弃了、累死了,这 Annotation Processor 是多麻烦,一个 AST 想解构还不容易啊…… 如果用 Visitor pattern 会方便很多,可我需要能够检查 path 的 Tree/Visitor,不知道有没有这种 API,这次只能暂时以二分查找最小的 (it >=k) 结尾吧,写点其他的吧…… #task
#PL 通俗的方法是使用 package javax.annotation.processing.util;
ElementScanner8<R, P>#scan(Element e);

《深入理解 Java 虚拟机》那本书教的不对啊!javax.annotation.processing 不能拿来修改和生成语法树节点啊!!!空欢喜我一场!
package javax.annotation.processing;
public interface Filer {...}
呀,不错嘛,还提供有能够生成代码的东西(这样 GeekSpec 就可以直接利用 Java APT 集成了,也是个好想法)。

一个 javac 包含 locale, options, sourceVersion, messager, filer, types, elements 等多个好用的组件或信息

可见 annotation processor 还是很强大的,有意思的是,Annotation processor 连 IDE 的补全 API 都有 getCompletions(e, AnnotationMirror, ExecutableElement, userText): Iterable<out Completion>
居然花了两个小时!不过好歹是写完了 #Java
name_checker.zip
22.3 KB
This media is not supported in your browser
VIEW IN TELEGRAM
想要学习一下怎么写 #Java Annotation Processor 的同学们快来看辣,花了我两个小时……
也是个好康的,比 《深入理解 Java 虚拟机(第二版)》上的那个还简单,我没检查 A__SNAKE 这种双下划线的情况,全用的 regex,而且没有一个类超过一百行代码,绝对很省事
(虽然 APT 也未必是一个怎么样的技术,不过了解一下入门总还是好的,起码可以基于元数据编译期静态代码生成)

import org.intellij.lang.annotations.Language;

public enum CaseJudge {
snakeCase("(_?\\p{javaLowerCase})+"), ...;

@FunctionalInterface interface Checker { boolean isValid(String name); }
final Checker checker;
CaseJudge(@Language("regexp") String regex) { this(s -> s.matches(regex)); }
CaseJudge(Checker checker) { this.checker = checker; }
}

可能没有比这个版本写的更简单的了…… 原版是基于状态机和索引字符 codePointAt(int) + java.lang.Character,十分不好看
就是用一个 Visitor Pattern (ElementScanner8<Void/*res*/, Void/*arg0*/>) 先序遍历来检查语法树里的名字