分类 未分类 下的文章

以下代码可以运行. 意味着可以使用回调函数

Function f1(x,y)
    return x + y
end Function
Function f2(x,y)
    return x - y 
End Function
Function a(f)
    Log.Info(f(1,2))
End Function
a(f1)
a(f2)

并且函数名除了作为形参,还可以作为普通变量以及对象的值

Dim f = f2
f('from f')

dim o = {
    'f': f1
}
dim o_f = o['f']
o_f('from o_f')

Function f1(s)
    Log.Info('f1')
    Log.Info(s)
End Function

Function f2(s)
    Log.Info('f2')
    Log.Info(s)

End Function

上面的用法,意味着可以创造类似于接口的功能,使用同一接口函数抽象调用,实际实现可以不同。
另外,也可以实现类似于面向对象的开发,在一个object中除了定义变量还可以定义函数。只是在对象中的函数不能直接写在对象里,也不能匿名,需要在外面写好,在对象里赋值。
同样的,对象里的函数也不能通过o['f']()的方式调用,需要先赋值给变量,再通过变量调用。

另外,发现在函数中使用这种方法会报错,似乎和编译有关:

Function a()
  dim f = f1
  f()
End Function

Function f1()
  log.info(f1)
End Function

报错: 后端错误 unexpected symbol near ')'
这种情况只要将dim f放到全局就会正常,不知道为何,似乎是回调函数名称必须为全局变量(常量), 如下:

dim f
Function a()
  f = f1
  f()
End Function

Function f1()
  log.info(f1)
End Function

另外,始终没有找到根据字符串常量表示的函数名调用对应函数的方法。

回调的坑: 跨文件调用回调会丢失全局环境(包括全局变量)

有一个主文件为test.task, 一个作为提供函数的模块文件tools.task, 如果在主文件中调用模块文件中的函数, 并给其提供的回调函数位于主文件中, 那么此回调函数不能访问主文件中的全局变量.
调用关系: 主文件->调用模块文件的函数(主文件的回调函数名)->调用主文件回调函数->丢失主文件全局变量. 示意如下:

/* tools.task 模块文件 */
Function funcInTools(cb)
    Log.Info('funcInTools')
    gCallback = cb
    gCallback()
End Function

/* test.task 主文件 */
Import tools
Dim gCallback
Dim gLost = 11 
funcInMain(cbInMain) // 通过主文件的函数调用主文件的回调函数, 不会丢失全局变量
tools.funcInTools(cbInMain) // 通过模块文件的函数调用主文件的回调函数, 丢失全局变量

Function cbInMain() //主文件中的回调
    Log.Info(gLost)
End Function

Function funcInMain(cb)
    Log.Info('funcInMain')
    gCallback = cb
    gCallback()
End Function

运行后输出如下:

[2024-4-24 11:42:04] [INFO] 流程 test.task 开始运行
[2024-4-24 11:42:04] [INFO] test.task 第15行:funcInMain
[2024-4-24 11:42:04] [INFO] test.task 第11行:11
[2024-4-24 11:42:04] [INFO] tools.task 第7行:funcInTools
[2024-4-24 11:42:04] [INFO] test.task 第11行:null

可以看到回调函数第一次调用可以输出全局变量, 而第二次调用则不可以.
这种情况建议将全局变量通过形参传入:

/* tools.task 模块文件 */
Function funcInTools(cb, 传入变量)
    Log.Info('funcInTools')
    gCallback = cb
    gCallback(传入变量)
End Function

/* test.task 主文件 */
Import tools
Dim gCallback
Dim gLost = 11 
tools.funcInTools(cbInMain, gLost) // 通过模块文件的函数调用主文件的回调函数, 丢失全局变量

Function cbInMain(传入变量) //主文件中的回调
    Log.Info(传入变量)
End Function

python中有cpca库, 可以匹配省市区并返回. 但这个库有些老, 好多年不更新, 像深圳龙华区这些近几年升级为区的都没有. 所以需要结合正则实现.
python还有另外一个geopy库也可以实现, 但是这个库需要实时通过API读取, 还总是timeout, 所以放弃这个方案.
UiBot本来支持python扩展来解决, 但是不知为何Uibot自带的python对cpca支持有问题, 始终报错, 所以放弃, 改为Uibot调用系统命令读取打印输出的方式曲线救国.
python代码都是GPT4 Turbo写的, 自己做了小修改.
Uibot测试:

PyTools('parse_address', '广东省深圳市龙华区深圳北站')

Uibot函数:

// 由于通过uibot的python调用存在问题(import cpca始终报错), 所以通过命令行调用
// python路径直接写在tools.bat中, 使用系统where python给出的路径, 避免uibot调用错误的python版本. 此时在系统中使用Pip安装的库可以直接在这儿使用
// tools.bat直接调用执行tools.py. 具体函数在tools.py中实现
// 以Json字符串形式返回
Function PyTools(func, params)
    // params支持单字符串的单参数或者数组形式的多参数
    Dim Ret
    If type('params') = 'string'
        Ret = Sys.Command(@res"tools.bat "+func+" "+params)
    else
        Dim cmd = @res"tools.bat "+func
        For Each p In params 
            cmd = cmd + " " + p
        Next
        Ret = Sys.Command(@res"tools.bat "+func+cmd)
    End if 
    return JSON.Parse(Ret)
End Function

系统命令 tools.bat和python脚本tools.py, 放在uibot项目的res目录下. 如果不放心调用哪个版本的python,可以积极在python前面加路径.

@echo off
python.exe D:\folder\to\project\res\tools.py %1 %2 %3 %4 %5 %6 %7 %8 %9
@echo on

tool.py部分. 大多数是gpt4写的

# tools.py

import sys,re,json
import cpca

def parse_address(address):
    a = ""
    a1 = parse_address1(address)
    a2 = parse_address2(address)
    # 策略: 长度相同优选a1方法, 否则选a2
    if len(a2) <= len(a1):
        a = a1
    else:
        a = a2
    # return f"{a[0]}|{a[1]}|{a[2]}"
    return json.dumps(a, ensure_ascii=False)

# 采用cpca获取省市区. 好处: 不写省市区这几个字都能识别. 问题: 可能有数据库过期问题(龙华区无法识别)
def parse_address1(address):
    # 使用 cpca 库解析地址并返回 DataFrame
    df = cpca.transform([address])
    location = df.iloc[0]  # 提取第一行数据,即我们需要的地址解析结果

    # 返回省市区字符串,用 "|" 分隔
    # return f"{location['省']}|{location['市']}|{location['区']}"
    return list(filter(None,[location['省'], location['市'], location['区']]))

# 采用正则表达式获取省市区. 好处: 不需要更新数据库. 问题: 必须有省市区这几个字.
def parse_address2(address):
    # 更新省/直辖市的匹配模式以处理没有“市”字的直辖市情况
    pattern = re.compile(
        r'(?P<province>[^省]+省|[^自治区]+自治区|北京|天津|上海|重庆)?'
        r'(?P<city>[^市]+市|[^自治州]+自治州|[^地区]+地区|[^盟]+盟)?'
        r'(?P<district>[^县]+县|[^区]+区|[^旗]+旗|[^自治县]+自治县|[^林区]+林区|[^特别行政区]+特别行政区)?'
    )
    match = pattern.search(address)
    if not match:
        return "无法提取地址信息"

    province, city, district = match.group('province', 'city', 'district')

    # 北京、天津、上海和重庆作为直辖市,如果匹配到省份但没有匹配到市,将省份的名字赋给城市
    if province in ['北京', '天津', '上海', '重庆'] and not city:
        city = province
        city = city + '市'

    # 如果没有匹配到,则用空字符串代替
    province = province if province else ''
    city = city if city else ''
    district = district if district else ''

    # 以"|"连接非空字符串
    # result = '|'.join(filter(None, [province, city, district]))

    return list(filter(None,[province, city, district]))

def test_parse_address():
    print(parse_address('广东省深圳市龙华区深圳北站'))


if __name__ == "__main__":
    if len(sys.argv) < 3:
        print("Usage: python tools.py parse_address 'Your Address String Here'")
        sys.exit(1)
    if sys.argv[1] == "parse_address":
        input_address = sys.argv[2]
        result = parse_address(input_address)
        print(result)
    elif sys.argv[1] == "test_parse_address":
        test_parse_address()
    else:
        print('["没有正确的函数名"]')

我: 请数据一个bat文件,可以接受一组参数. 参数为ot时, 将使用ssh命令登录到192.168.1.105端口8022上, 参数为om时, 将使用ssh命令登录到192.168.0.31端口8022上

GPT: 以下是一个能够接受参数的批处理文件的示例:


@echo off

REM 检查传入的参数
IF "%1"=="ot" (
REM 执行连接到192.168.1.105:8022的ssh命令
ssh user@192.168.1.105 -p 8022
) ELSE IF "%1"=="om" (
REM 执行连接到192.168.0.31:8022的ssh命令
ssh user@192.168.0.31 -p 8022
) ELSE (
REM 未提供有效参数时显示帮助信息
echo 请提供有效参数(ot 或 om)
)

REM 结束批处理文件
exit /b


> 请注意,上面的示例假设已经安装了ssh客户端,并且可以通过命令ssh来进行远程登录。

实际运行一次性成功

参考: 2024,像极了1929

这篇文章作者至少在一开始提出了2个真实的、不忽悠人的看法:一是绝大多数人成功自以为是实力实际上是运气;二是在运气产生的时候坚决地迈出去。不靠运气而能洞察未来的人不是没有而是很少。
所以这儿虽说是洞察,也只能把握大趋势,具体到适合个人的小方向上,只能提高好运气的概率。
文中2点和我想的也类似。其一是GPT之类的人工智能是新变革的起点,以后会变成日常生活的一部分,从现在开始在日常中应该更多应用AI;其二是中国尤其是深圳有制造业的优势,在全球都是最好的,如果不加利用非常可惜。
文中对AI有个观点,就是需要与各行各业深入结合,变成“蒸汽机”,深刻提高效率以至于创造力。
文中对中国制造业有两个值得注意的观点:制造业不应像美国一样完全外流,在扩展到海外的同时,而应在国内同时保留一份;另一个是世界级的领导者企业应该、也必然更多在中国产生,也就是更多颠覆者,而不仅仅都是跟随者。我倒是认为颠覆者已经渐渐产生,至是不够深入和全面。目前主要是在互联网领域,比如字节的Tiktok是世界首创的短视频平台、腾讯的微信也让马斯克的X模仿。为什么?因为这个领域进入成本低,一个人有一台电脑就搞定了,创新速度也就更快。字节可以说是靠今日头条积累原始资本,靠抖音发财成为全球现象级产品。对于制造业的个人创新,以前门槛是比美国人高很多的。美国人都有个车库,里面钉锤斧钻样样俱全,从小再这样的环境中长大的人,很容易在鼓捣出些创新硬件产品。中国都住在鸽子楼里缺少这样的环境,然而近年B站不少UP主也利用家里环境和1688的便捷采购鼓捣出不少新玩意。再加上很多硬件设计可以通过电脑完成,如果加上AI的助力,是否能形成一波硬件产品创新的浪潮,就像美国发明了电灯泡洗衣机,日本让磁带、Walkman、游戏机走入每个家庭一样。
现在AI的问题有以下几个,在解决以后,会形成很大助力(我相信近几年会很快解决):

  • 缺少大量的人工信息导入和分析能力。比如AI和爬虫结合, 通过爬虫给AI导入大量的信息, 让AI对解决方案中的原料进行快速寻找、匹配,甚至对解决方案进行自动优化
  • 缺少通用的图片分析能力。根据图片分析产品的尺寸、材质、重量、结构、功能等是否适用。
  • 缺乏数学和逻辑推理能力。
  • 缺乏复杂的编程和自我DEBUG验证能力。
  • 缺乏工程设计图、矢量图、3D图的阅读和编辑能力。比如可以自编辑STEP文件、SVG文件、STL文件等。现在的AI能力主要是位图能力。
  • 事实上其他文档的生成能力也还很初级,比如xlsx等。
    这些方面应该会在近几年快速补齐。有的是AI能力已经足够,只是缺少对应的应用,有的还需要AI本身去提升能力。

希望做一个功能, 通过收集表收集的数据在处理完成后删除掉. 哪种删除方式最方便有效

1. 直接删除统计表: 失败

直接删除统计excel表后, 点击在表格中查看按钮, 会显示表格已经删除, 而且新建相同名称的表格也不能恢复

2. sheet重命名: 失败

重命名sheet后, 仍然在重命名后的sheet中添加数据, 并不能新建sheet添加新数据

3. 在搜集表-统计-已填写-三个点, 一个一个点击移除 : 成功50%

确实可以从统计表sheet中移除数据, 那一行会变成「已移除」, 但是这一行依然存在, 新数据不会覆盖这一行

4. 直接删除统计表数据行: 成功100%

删除数据行后, 新的数据会从新的一行开始

5. 删除sheet后重新关联统计表: 失败

删除sheet后, 可以点击统计表右上角三条杠菜单, 选择'关联的内容', 然后选择对应的收集表, 此时会新建一个收集表同名sheet, 如果已有同名sheet则在名称后面加(1), 而且, 此时会把过往删除的所有收集表信息统统恢复出来.

我们对运气缺乏敬畏,我们对能力过于自信。

运气三角

运气-预测-努力
运气是个体主观上无法把握,但客观上在未来呈一定概率影响个体的事件,是未知的未来,简称为运。
预测是对个体对局势的认识,简称为势,可个体主观上可以了解和把握的未来事件。因为预测是主观的,所以未来未必一定发生。
运气和预测合称为运势。运与势的比例并非一成不变,个人的认识越深刻,就能更多减少运的成分而增加对势的把握。但因为个体的认识必然存在的局限性、以及人类当前知识的局限性,不可能完全杜绝运气成分。
努力是个人为了自己的预测的方向所做的付出。没有方向的付出只能称之为勤奋,也叫做碌碌无为。

运气与希望

“希望”是主观上认为存在可能的好运气,但不一定符合客观事实。但只要存在希望,人就会有努力的动力。
买彩票其实主观希望和客观运气相对偏离不大,因为中彩票的概率是相对容易计算的。
但对未来的希望与运气可能存在较大偏差。这往往是由于个体方向感不强,缺乏对局势的认识。个体容易以近一年的经验去理解余生可能发生的事件,从而产生较大偏差。

运气与奋斗

有些90年代从国企去沿海打工创业的,大多有想法、有能力、肯奋斗,然而在20~30年后,由于商海浮沉,多数仍然没有积累很大财富;而在国企中能力平庸、也没有胆量出来打拼的,20~30年后往往成为高管甚至一把手,享有很高的待遇。从财富角度来讲,在我国的优质国企长期做下来,比在外面打拼奋斗似乎积累了更多财富。创业者把握了方向,但创业的好运气并不多;国企人没有把握方向,却沾上了好运。
2000年开始,中国商品房改革后房价快速上涨,那些结婚早迫于丈母娘压力买房的,最后都笑开了花,那些不愿背负房贷、甚至想要用资金创业的,最后越来越买不起。一个是被迫躺赢,一个是主动奋斗到输光。
上面只说了两个结果与奋斗成反比的例子,是因为成正比的例子更多,翻开几乎任何一个成功人士和成功公司所宣扬的个人奋斗史、公司历史,几乎无不再宣示自己的成功都是自己的勤奋奋斗的结果。
因为历史是胜利者书写的,失败者没有书写历史的权利,因为失败者没有书写的资本、也没有书写的信誉。
然而事实是,多数胜利者只是幸运儿而已。一将功成万骨枯才是现实。多数胜利者的“奋斗等于成功”的故事,只是幸存者偏差罢了。
也有极少数的胜利者,通过深刻的认识把握了正确的方向,不但顺势还能造势。马斯克、王传福、查理芒格是其中佼佼者。
商业竞争中,有一种既得利益者对后来创业者的“看不见、看不起、看不懂、跟不上”的情况(应该是马云所说),这就更说明了这种既得利益者的利益来源是某种运气而已。

对运气的认识之路

由于学校和家庭教育的缘故,在走向社会之前,我一直认为获得成就是靠能力。这儿我跳过了“努力”这一步,因为那时我没怎么努力也获得了很好的成绩,幸运地没和其他考试竞争者一起“卷”。还有一个原因是初中时读了郑渊洁的一部童话作品,其中提到了老子的“唯不争天下莫能与之争”,所以也不愿意卷,当然那时候也还没有深刻地理解这句话的意思。走向社会后,正好碰到中国经济的大发展,需要有能力的人,去了很顶级的公司,这时候对能力的迷信达到了顶峰,认为有能力就能做成一切事情。其实,说到底,广义上的努力也是包括能力的,能力只能通过努力训练得来。只不过有些人由于兴趣等使然,可以不使用“强迫自己的那种努力”主动地训练获取能力,即使用了“兴趣”。
直到三十多岁经历过几个创业公司后,对获得成就又有了新的认知。这时候认为要靠胆识。也就是能够认识到事物发展的方向,并且有胆量去部分或者完全投入这个方向,然后获取成功。这时候,就在找这样的经过成就验证的创业领袖,也就是他依靠其胆识获得了一定成就,并且对同伴非常好的人,认为以其被验证的胆识,必然会继续做出新的成就。这时候已经认识到能力不是关键了,有胆识者,自然会招募到有能力之人来帮自己完成。
对运气的认识,是最近几年的事情,人其实已经到了四十岁左右。自己所认为的有胆识的领袖节节败退屡屡受挫,使自己不得不对曾经坚定的信念怀疑起来。加上疫情以来,众多曾经只能仰望的大佬忽然败的败,跑的跑(乐视恒大等不胜枚举),意识到这些大佬曾经的成功并非全是能力,也并非全靠胆识。过去的成功即使在同一个人身上都难以复制,为什么?因为世界上有太多他们都无法预测之事,而他们有很多相信自己可以预测。预测成功了则是胆识过人,失败了则快速被人遗忘。为什么我过去很难意识到这一点?第一,从教育体制到社会舆论到企业自己的宣传,都不可能承认成就里面有很大运气成分,运气无法把握更无法教育,企业也不可能说自己是凭运气做得这么成功(但失败的时候企业却会说运气不好);第二,疫情前的几十年中国经济快速向上发展,好运气的概率非常大,所以相对容易成功,并且容易反复成功。而现在国家增速放缓,好运概率也大大下降了。
有没有全靠胆识不靠或少靠运气的?有,但是这种人极少极少。所以遇到一个成功的人,可以先断定其中大概率有相当运气成分。接下来他能不能继续成功,就是看他以前的成功的运气成分有多少,以后还有没有这么好运了。
进一步的,如果有人承认自己的成功有很大运气成分,那么他真的可以称得上自我认知清晰、诚实、且高尚了。近的有罗翔老师,远的如寒窑赋(即便是伪托吕蒙正)所说:“人道我贵,非我之能也,此乃时也、运也、命也”。

外观和结构3D文件.STEP处理能力: 失败

.step文件是基于文本的,GPT3.5 可以像模像样的生成,但无法读取, 应该是格式有错误。GPT4则直接拒绝了。

SVG文件处理

绘制APP图标的任务GPT3.5和GPT4都可以实现, 相对来说GPT4实现得更好一些, 不过也需要两三轮的调试对话. 另外, 两者对常见图标的理解会更好, 而不常见的抽象图标的理解就不太到位. 不过还是能给出一些提示的.
更复杂的svg文件输出, GPT4会直接拒绝, 而GPT3.5则来着不惧. 如下面这个任务: 请输出svg代码, 用于表示一个在坐标系中的高斯曲线, 曲线中用虚线表明中位数、-1SD、-2SD、+1SD、+2SD的位置。 GPT4表示我不行,而GPT3.5则输出了一段代码,虽然效果比较差。不知道GPT3.5算不算是无知者无畏?😊
不过如果真的是去找SVG格式的图标的话, 还是不如iconfont更快些.

小程序处理

纯JS的撰写无疑是可以胜任的,但是涉及js/wxml/wxss是否可以胜任? 测试对GPT3.5确实是可以的。

参考https://mp.weixin.qq.com/s/nZNB9XbqqobgtIEdcB411g

文章后面的一句话让我印象是深刻:

当我的孩子长大成人,我们看待“程序员”的方式,就像我们现在回顾“计算机”发展历史一样。自己敲打 C++或 Python 代码,最终可能看起来像在打孔卡上发出二进制指令一样荒谬。

所以,应该从历史的观点来看,AI或者说GPT为代表的生成式AI会是什么?会替代掉什么?
毫无疑问,AI将成为未来我们每个人生活的一部分。问题是多大一部分?如果AI是互联网、是电脑、是手机,那么在5~10年后(甚至不要那么久),它就会像网络、电脑、手机一样,成为我们每天、甚至每一小时的一部分。

易事做难的味道

很多事情原本是可行的,但是由于考虑太多,希望一次性做得更好更完美,而迟迟无法行动。
人品尝这个味道的表现是:事情连续几小时甚至几天停留在大脑中或草稿纸上,人感到疲倦、甚至一想到这个事情就打瞌睡。
如何改变:应该立刻使用不完美的方案行动起来。不怕犯错误,要在错误中学习;不怕因不完美而推翻重构;不要指望在第一代成果(产品、方案……)中就完美解决大部分问题;在行动中获得的反馈要比大脑和草稿中多得多。
要将难事做易,而不是相反。

怕麻烦的味道

不怕失败,但要避免失误导致的失败。什么是失误,就是原本知道也能做到的,却没有做到。这常常是因为怕麻烦,因为侥幸心理而省略中间步骤,甚至是在潜意识中形成的。
人品尝这种味道的表现是:在没有经验、首次尝试的事情上面限制了完成时间;着急完成,并感到心浮气躁;如果有人此时打扰自己,自己脾气会非常差;缺少必要的检查、验证、拆解;希望并尝试走捷径。
如何改变:在首次尝试的事情上面要感到敬畏,如用手电进入黑房间,每次只能看到一个光斑,要不怕麻烦,仔细照到每一处角落,对看到的结果并做好应对措施,即使角落弯弯绕绕,即使措施要层层叠叠,都要仔细完成;去掉时间限制;或者做好在预想时间内不能完成的准备工作;不要贸然获取最后的结果,直到自己平静地感到所有准备工作都已经完成;时刻警醒自己,怕麻烦的结果是成倍的麻烦、成倍的时间和金钱成本。

理所当然的味道

这世界上理所当然的事情要比想象的多得多。所有没有经过自己质疑就相信了的事情,都是理所当然的。然而所有理所当然的事情,都不是必然如此的。
人品尝这种味道的表现是:不经过调查和思考,就拒绝别人提出的想法;拒绝新的概念、工具、方法等。
如何改变:因为人的精力有限,所以绝大多数的事情都不可能深入调查,而是被别人教育、洗脑几个月甚至几十年。在做任何判断前,要时刻意识到这一点,自己的潜意识和固有观念中的很大一部分是被其他人洗脑的结果,是其他人基于他们的宣传期望和宣传能力让自己这样认为的。

历史包袱的味道

每个人都会有自己的精神历练(经验值), 还会有自己的物质积累(有形物质库存, 这儿把金钱除外)。 这两者用得好对自己是助力, 用得不好对自己是包袱。
经验值就像数学公式, 只有在现在和未来的情景与过去完全相同或几乎相同的时候才是助力, 一旦情景差异变大, 乱套公式只会得出错误的结果。 多数人在获得自己的经验的时候, 并不会记忆经验得出的情景条件, 那么在应用经验的时候, 也不会注意当前和未来情景与经验情景有多少不同。
物质积累也是这样, 多数在过去值钱的物质, 现在和未来往往不值钱, 还难以变卖。 有形物质有三个问题, 一是本身占用库存, 二是绝大多数具有保质期, 三是相对金钱更难以流通。 信息时代金钱的流通以秒计算, 而物质流通最快以天, 长则以月甚至以年计算。 多数有形物质的价值有峰值,峰值过后,价值和流通性都会快速下降。而多数人习惯以自己购买时候的价值衡量,并且不考虑库存、保质期和流通性。在这部分物质不能以期望的价值流通的时候,往往又期望未来自己做什么事情又能用到这部分物质,实际上潜意识是拖延不决。
中老年人尤其容易产生历史包袱的坏味道。因为人类基因进化的漫长历史,环境往往不变,物质往往稀缺,经验和物质总是有用。所以人们本身缺乏避免这种坏味道的基因。
人品尝这种味道的表现是:一开始就拒绝承认变化;或者尝试适应变化,但浅尝辄止,害怕深入后丢掉自己的经验;也不愿放弃过往的社会关系;不愿丢弃自己曾经花钱购买的东西;想要把别人不要的东西、但购买又很贵的东西拿回来,忽视其库存占用、保质期或流通性。
如何改变:仍然是旧的不去,新的不来。对旧的经验要扬弃,了解其长处和弱点;对新的变化要敢于深入尝试,忘记自我,不受过往经验约束;对于物质积累,要像供应链管理一样追求高周转、零库存,也就是抵制消费主义,拥抱极简生活。只保留自己真正在使用的部分物质。物质如果不是用作证据存留,与其吃灰不如换成高流动性的其他资产或资金。

提前声明, 个人观点, 仅供参考.

喝桶装水, 哪种产品更好?




以上3种饮水机/抽水机哪一种更好?
一二三分别是立式饮水机,电动抽水机和手动抽水机.
当然每个产品都有各自的定位, 有各自的受众和市场. 但从第一性原则上说, 我认为第二种更好.
第一种传统的大饮水机, 几个问题: 占地/反复烧开浪费能源/换水落灰长期滋生细菌/烧的开水多数时候是兑了凉水/即使烧了开水储水量也很小泡茶泡面都不太够/开水也不够高温会储存晾凉. 第三种按压机械式当然非常简洁, 不过喝水作为一个非常高频的动作, 应该更省力.
第二种电动抽水机, 小巧, 容易安装, 没有储水结构, 不会积灰也不会反复烧开. 可以电加热为温水足以满足绝大多数饮水情形. 要开水的话, 几乎都会有电热水壶完成.

修剪鼻毛,哪种产品更好?



一二三分别是电动鼻毛修剪器/手动修剪器/圆头剪刀.
我认为第二种更好.
修剪鼻毛其实是比较低频的操作, 不可能天天修剪. 由于电池自然放电, 第一种电动的可能用不了几次就没电了, 而且清洁起来也要麻烦些. 体积也稍大一些. 第三种剪刀还是容易让人有恐惧心理, 毕竟鼻毛根部隐藏在鼻孔中是看不到的, 让人感觉必须小心翼翼去修剪.
第二种手动修剪器, 当然不必担心没电的问题, 另外不锈钢全身随便怎么洗都没有问题, 体积也小巧容易收纳.

在一个具备数据增删改功能的页面中, 一种呈现增删改操作的常见方式就是对话框. 微信Weui中的mp-dialog组件的控制, 在js中一般需要下面五六种对象和函数

  • data中控制对话框显示的isShowDialog布尔变量
  • data中展示对话框中按钮的dialogButtons数组变量
  • 触发对话框显示的函数showDialog
  • 点击按钮后触发的, 与mp-dialog的bindbuttontap绑定的tapDialogButton函数
  • 隐藏对话框的函数. 因为比较简单,一般集成在tapDialogButton中
  • 处理实际增删改的函数如add
    显得特别复杂.增删改各一个对话框,上面就得来3套, 15~18个.
    考虑将dialogButtons/showDialog()/tapDialogButton()合并, 不同的对话框共用一套按钮/显示/隐藏/处理按钮函数.以add为例, 如下:
<view bind:tap="showDialog" data-show="isAddDialog">显示对话框</view>
<mp-dialog title="新增目标" show="{{isAddDialog}}" bindbuttontap="tapDialogButton" data-show="isAddDialog" data-func="add" buttons="{{dialogButtons}}">
对话框内容
</mp-dialog>
Page({
  data: {
    dialogButtons: [{text: '取消'}, {text: '确定'}], // 通用的对话框按钮列表
    isAddDialog: false,
  },
  showDialog(e){
    this.setData({
      [e.currentTarget.dataset.show]: true
    })
  },
  tapDialogButton(e){
    console.log(e)
    switch (e.detail.index) {
      case 0: // 取消   
        this.setData({
          [e.currentTarget.dataset.show]: false
        })
        break;
      case 1:
        console.log('dialog running ', e.currentTarget.dataset.dialog)
        let ret = this[e.currentTarget.dataset.func](e)
        // 返回值为true时表示成功处理, 则隐藏对话框
        if(ret){        
          this.setData({
            [e.currentTarget.dataset.show]: false
          })
        }
        break;
    }
  },
  add(e){
    // 对数据进行处理
    return true
  },
})

阿里云官方原文
不但减到了3个月, 而且免费额度还是20个不变, 想要12月的证书就要68元一张. 这是非要我们付费不[]可吗.
知乎上有个答案, 建议申请https://certsvc.com/的二级域名通配符证书. 这个证书是50元一年.
另外,在gitee上有一个certd的项目, 声称是完全免费部署
上面这个项目提到了一个免费ssl提供商letencrypt

let's Encrypt和acme.sh

这儿介绍了let's encrypt 的部署, 以及github的acme.sh项目.
推荐使用这个项目进行ssl证书的申请. 申请下来后,部署都好说了.
对于阿里万网的云虚拟主机, 参考这个官方说明
Let's encrypt支持三种证书:单域名证书, 泛域名证书(SAN证书), 通配符证书.
这儿文章介绍如何用acme.sh为阿里云域名申请泛域名证书. 这儿是acme.sh支持阿里云的官方文档.

certbot

知乎这个文章介绍了通配符证书工具certbot

在gitee上开了个项目做这个测试: https://gitee.com/littleprog/js_efficiency

测试结果

Array add 10M elements 3 times (by push) 
time diff:  284
time diff:  363
time diff:  226
Array add 0.1M elements 3 times (by unshift. unshift is really slow, so I use 1% elements of 10M)
time diff:  737
time diff:  703
time diff:  736
Object add 10M elements
time diff:  244
time diff:  294
time diff:  249
 Array delete 10000 elements(by splice from beginning)
time diff:  636
 Object delete 10000 elements
time diff:  1
 Array modify 10M elements 3 times
time diff:  8
time diff:  7
time diff:  8
 Objec modify 10 elements 3 times
time diff:  8
time diff:  8
time diff:  7

总结

  • 新增: Array用push新增元素和Object效率差不多, 但是用Unshift新增元素效率惨不忍睹, 效率极低, 在增加的数据量为100K时已经接近1秒时间, 而且估计随着array的变大会越来越低. 所以array的内存块是连续的, unshift是内存整体向后移动后再在前面增加元素的.
  • 删除: 同样, 如果array用splice删除排序靠前的元素, 效率也是远远低于使用delete删除Object中的元素.
  • 修改: 两者的修改不存在区别.

因此, 对于元素数量极多并且需要随机插入数据和删除数据时, Object才是更好的选择. Array有一个Object没有的功能是Array元素是有序的, 而Object元素是无序的. 虽然Object可以将key值设置为序号, 表现为类似Array的顺序, 但是在随机增加和删除后, 这些序号会被打乱. 事实上, Array比Object低效的部分, 恰恰就是在排序上花费了额外的时间, 每次插入和删除一个元素时, 相当于要将其后面的所有元素序号变更. 另外, array还有个特点是支持for of循环, 也就是本身是一个迭代器iterator
我猜测NoSQL数据库, 包括腾讯小程序的云数据库, 都是用的Object的方式存储不同条的数据的. 其_id相当于是key, 这样随机查找增加删除都比较快. 而排序是需要单独的sort命令, 因为object本身是无序的. 并且经常使用某一个属性排序或者查找时, 还需要预先进行升序或降序索引, 否则数据量大了以后速度估计会惨不忍睹.
所以在本地对大数据量操作时, 要提前考虑好是使用array还是object. 如果必须要有顺序或者要使用迭代器的特性, 那么就只能用array了.