91

如果你是一个Golang面试官,你会问哪些问题? - 知乎

 6 years ago
source link: https://www.zhihu.com/question/67846139/answer/257359743?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

如果你是一个Golang面试官,你会问哪些问题?

想问下假如你是golang面试官你会问哪些问题!
1,923
432,298
登录后你可以
不限量看优质回答私信答主深度交流精彩内容一键收藏
眼里不容沙,笑里不藏刀。萌即正义~

这篇文章翻译自一位外国友人的关于面试后端程序员的文章,我比较喜爱这篇文章。一是因为它极大的拓宽了我的视角,另一方面是其中的一些问题非常具有启发性。不仅对于面试者,对于面试官来说也是个不错的参考。于是迫不及待的翻译了一下,给各位看官做个参考。

原文参见 @arialdomartini的: Back-End Developer Interview Questions

以下是原文翻译。

  1. 开放式问题
  2. 设计模式相关问题
  3. 代码设计相关问题
  4. 语言相关问题
  5. Web相关问题
  6. 数据库相关问题
  7. 非关系型数据库相关问题
  8. 代码版本管理相关问题
  9. 分布式系统相关问题
  10. 软件生命周期和团队管理相关问题
  11. 逻辑和算法相关问题
  12. 软件架构相关问题
  13. 面向服务架构(SOA)和微服务(Microservice)相关问题
  14. 安全相关问题
  15. 比尔盖茨式问题
  16. 代码示例问题

通用问题:

  • 语言设计中空引用(null reference)的存在有什么问题?假设你想要将空引用的概念从你的首选语言中移除,可能导致什么结果?
  • 为什么函数式编程重要?什么时候适用函数式语言?
  • 设计(design)、架构(architecture)、功能(functionality)和美学(aesthetic)之间有什么区别?讨论一下。
  • 微软、谷歌、欧朋(opera)和火狐这类公司是如何从他们的浏览器中获利的?
  • 为什么打开TCP套接字有很大的开销?
  • 封装的重要性体现在哪儿?
  • 什么是实时系统?它与普通系统有什么区别?
  • 实时语言(real-time language)和堆内存分配(heap memory allocation)之间的关系是什么?
  • 不变性(Immutability)是指: (变量的)值只能在创建的时候被设置一次,之后就不能被改变。为什么不变性对写更加安全的代码有帮助?
  • 可变值(mutable values)和不可变值(immutable values)有哪些优缺点?
  • 什么是O/R阻抗失衡(Object-Relational impedence mismatch)?
  • 如果你需要使用缓存,你使用哪些原则来确定缓存的大小?
  • TCP和HTTP有什么区别?
  • 在客户端渲染(client-side rendering)和服务端渲染(server-side rendering)之间,你是如何权衡的?
  • 如何在一个不可靠的协议之上构建一个可靠的通信协议?

开放式问题:

  • 为什么人们会抵制变化?
  • 如何向你的祖母解释什么是线程?
  • 作为一个软件工程师,你想要既要有创新力,又要产出具有可预测性。采用什么策略才能使这两个目标可以共存呢?
  • 什么是好的代码?
  • 解释什么是流(Streaming)和如何实现一个流?
  • 假设你的公司给你一周的时间,用来改善你和同事的生活: 你将如何使用这一周?
  • 本周你学了什么?
  • 所有的设计中都会有美学元素(aesthetic element)的存在。问题是,你认为美学元素是你的朋友还是敌人?
  • 列出最近你读过的5本书。
  • 假设目前有个大型公司(非常有钱),他们的开发流程是瀑布式流程(Waterfall),如果需要你在他们公司引入持续交付(Continue Devivery),你会怎么做?
  • 我们来谈谈"重复造轮子","非我发明症", "吃自己做出来的狗粮"的这些做法吧。

(注: 重复造轮子: Reinventing the wheel; 非我发明症:Not Invented Here Syndrome; 吃自己做出来的狗粮: Eating Your Own Dog Food)

  • 在你当前的工作流中,什么事情是你计划下一步需要自动化的?
  • 为什么写软件是困难的?是什么使软件的维护变得困难?
  • 你更喜欢在全新项目(Green Field Project)上工作还是在已有项目(Brown Field Project)基础上工作?为什么?
  • 当你在浏览器地址栏输入google.com回车之后都发生了什么?
  • 当操作系统CPU处于空闲的时候,它可能在处理哪些事情?
  • 如何向一个5岁的孩子解释什么是Unicode/数据库事务?
  • 如何维护单体架构(monolithic architecture)?
  • 一个"专业的开发者"意味着什么?
  • 软件开发是艺术、是技艺还是工程?你的观点是什么?
  • "喜欢这个的人也喜欢...",如何在一个电子商务商店里实现这种功能?
  • 为什么在创新上,企业会比创业公司慢些?
  • 为什么说,你不应该尝试应用自己发明或者设计的密码学?

设计模式相关问题:

  • 请用一个例子表明,全局对象是邪恶的存在。
  • 假设你工作的系统不支持事务性,你会如何从头开始实现它?
  • 什么是好莱坞原则(Hollywood Principles)?
  • 关于迪米特法则(最少知识原则): 写一段代码违反它, 然后修复它。

(注: 迪米特法则:the Law of Demeter, 最少知识原则: the Principle of Least Knowledge)

  • Active-Record模式有什么限制和缺陷?
  • Data-Mapper模式和Active-Record模式有什么区别?
  • 空对象模式(Null Object Pattern)的目的是什么?
  • 为什么组合(Composition)比继承(Inheritance)更好?
  • 什么是反腐败层(Anti-corruption Layer)?
  • 你可以写一个线程安全的单例(Singleton)类吗?
  • 数据抽象(Data Abstraction)能力是指能改变实现而不影响客户端的这种能力。请构造一个一个例子,违反这个特性,并且尝试修复它。
  • 你是如何处理依赖关系地狱(Dependency Hell)的?
  • 为什么说goto语句是恶魔般的存在?
  • 健壮性是进行软件设计时的一个通用原则,它建议 “发送时要保守,接收时要开放”。这也经常被写成,“做一个有耐心的读者,做一个谨慎的作者”。你能解释一些这背后的逻辑吗?

译者注: "发送时要保守,接收时要开发"的原文是: "Be conservative in what you send, be liberal in what you accept",有点类似于“严于律己,宽于待人”的意味。

代码设计相关问题:

  • 你在进行软件设计时会考虑软件测试吗?软件测试是如何影响软件设计的?
  • 内聚和耦合的区别是什么?
  • 重构在哪些场景下有用?
  • 代码中的注释有用吗?
  • 设计和架构有什么区别?
  • 为什么在测试驱动开发(TDD)中是先写测试,再写代码?
  • C++支持多继承,Java允许类实现多个接口。这些特性对正交性有什么影响?使用多继承和使用多接口有区别吗?[这个问题来自Andrew .Hunt 和 David Thomas写的《程序员修炼之道》]
  • 在存储过程(Stored Procedures)中写业务逻辑有什么优缺点?

语言相关问题:

  • 告诉我你的首选语言的三个最坏的缺陷。
  • 为什么现在函数式编程这么越来越受关注?
  • 闭包是什么?它有什么用途?闭包和类有什么共同点?
  • 泛型有什么用途?
  • 什么是高阶函数?有什么用途?用你的首选语言写个例子出来。
  • 讨论一下,如何写一个循环,然后把它转换成递归函数,要避免易变性。
  • 有些语言将函数视为第一公民,这是什么意思?
  • 用一个例子说明匿名函数是有用的。
  • 什么是动态方法调度(Dynamic Method Dispatch)?
  • 名字空间(Namespace)有什么用?有什么可以替代它的吗?
  • 谈谈Java和C#之间的互操作性(Interoperability) (任选其他两门语言都行)
  • 为什么很多软件工程师不喜欢Java?
  • 你认为好的语言好在哪里?差的语言差在哪里?
  • 写两个函数,一个是"引用透明的(Referentially Transparent)",另一个是"引用不透明的(Referentially Opaque)"。讨论之。
  • 什么是栈?什么是堆?
  • 为什么一个语言中,"函数是第一公民"是很重要的?
  • 模式匹配(Pattern Matching)和Switch语句(Switch clauses)的区别在哪儿?
  • 为什么有些语言设计上没有异常机制?这有什么优缺点?
  • 如果Cat是一个Animal, 那么TaskCare<Cat>是一个TakeCare<Animal>吗?

web相关问题:

  • 为什么"第一方cookie(first-party cookie)"和"第三方cookie(third-party cookie)"被如此不同的对待?

数据库相关问题:

  • 如果要你将一个项目从MySQL迁移至PostgreSQL中,你会如何迁移?
  • 为什么SELECT * FROM table WHERE field = null不能匹配空的字段?
  • 什么是ACID(原子性,一致性,隔离性,持久性)原则?
  • 你是如何进行数据库模式(Database schema)迁移的?
  • 延迟加载(lazy loading)是如何实现的?什么场景下有用?他有什么缺陷?
  • 什么是N+1问题?
  • 如何找出应用中开销最大的查询?

非关系型数据库相关问题:

  • 什么是最终一致性(Eventual Consistency)?
  • 关于CAP理论,举一些CP、AP、CA系统的例子。
  • NoSQL是如何解决可伸缩性的挑战的?
  • 什么情况下你会使用类似于MongoDB的文档数据库而不是关系型数据库(如Mysql或者PostgreSQL)?

代码版本管理相关问题:

  • 为什么在Mercurial或者git中(管理)分支比SVN容易?
  • 分散式版本控制系统(比如git),相比集中式版本控制系统(如svn)有哪些优势和劣势?

(注:集中式版本控制系统: Centralized Version Control Systems;分散式版本控制系统: Distributed Version Control Systems)

  • 能描述一下什么是GitHubFlow和GitFlow工作流吗?
  • 什么是rebase
  • 为什么合并操作(merge)在Mercurial和git中比在SVN和CVS中容易?

并发问题:

  • 为什么我们需要并发呢?解释一下。
  • 为什么测试多线程/并发代码这么困难?
  • 什么是竞争条件(Race Condition)?用任何一个语言写一个例子。
  • 什么是死锁?用代码解释一下。
  • 什么是饿死?
  • 什么是Wait-Free算法?

分布式系统相关问题:

  • 怎么测试一个分布式系统?
  • 什么场景下你会在两个系统中采用异步通信机制?
  • 远程过程调用的通用缺点是什么?
  • 如果你为了可扩展性和鲁棒性而构建一个分布式的系统,分别在封闭安全的网络环境情况下,和地理上的位置不同但是网络环境不是封闭和安全的情况下,你会考虑什么不同的事情?
  • 在Web应用中如何管理容错性?在桌面端呢?
  • 在分布式系统中,如何处理故障?
  • 让我们来谈谈网络分裂(network partitions)后有的几种恢复的手段吧。
  • 你认为分布式计算中有哪些谬论?
  • 你在什么时候会使用Request/Response模式,什么时候使用Publish/Subscribe模式?

软件生命周期和团队管理相关问题:

  • 什么是敏捷(Agility)?
  • 你是如何处理遗留代码(Legacy Code)的?
  • 假设我是你们公司的CEO,请向我解释什么是看板,并且说服我在它上面投资。
  • 敏捷(Agility)和瀑布(Waterfall)之间的最大区别是什么?
  • 作为团队管理者,你对会议太多这个问题是如何处理的?
  • 你会如何处理延期很长时间了的项目?
  • "个体与交互重于过程和工具"和"客户协作重于合同谈判"占了敏捷宣言(Agile Manifesto)的一半,谈论一下这两个观念。
  • 如果你是你们公司的CTO,你会采取什么样的决策?
  • 你觉得项目经理有用吗?
  • 如果要你组织一个弹性工作制的开发团队(即没有强制工作时间的要求),并且假期制度是"按需休假",你会如何做?
  • 你会如何管理一个人员流动非常高的团队?如何在不加薪的条件下说服团队成员不要离开?
  • 除了代码之外,你最关注你的同事的哪3项素质?
  • 关于代码,你最希望非技术人员能知道的的三件事是什么?

逻辑和算法相关问题:

  • 只用LIFO栈如何构造一个FIFO队列?只用FIFO队列如何构造一个LIFO栈?
  • 写一段有栈溢出的代码。
  • 写一个尾递归版本的阶乘函数。
  • 使用任何一个语言,写一个REPL,功能是echo你输入的字符串。然后将它演化成一个逆波兰表达式的计算器。
  • 如果需要你设计一个文件系统磁盘碎片整理程序,你会如何设计?
  • 写一个生成随机迷宫的程序。
  • 写一段有内存泄漏的示例代码。
  • 随机生成一个的数字序列,里面每个数字都不同。
  • 写一个简单的垃圾回收系统。
  • 使用任何一门语言,写一个基本的消息代理。
  • 写一个基础的web服务器,然后画一张线路图,展示你将来还想要实现的功能。
  • 如何对一个10GB的文件进行排序?如果是10TB的数据,你会采用什么方法?
  • 请实现rnd()函数

软件架构相关问题:

  • 什么情况下缓存是没用的,甚至是危险的?
  • 为什么事件驱动的架构能提高可扩展性(scalability)?
  • 什么样的代码是可读性强的代码?
  • 紧急设计(Emergent Design)和演化架构(Evolutionary Architecture)之间的区别是什么?
  • 横向扩展(scale out) vs 纵向扩展(scale up): 有什么区别?分别在什么场景下使用?
  • 分布式系统中如何处理"故障切换(failover)"和"用户会话(user session)"?
  • 什么是CQRS(Command Query Responsibility Segregation)?他和最早的Command-Query Separation原则有什么区别?
  • 什么是三层架构?
  • 如何设计一个可扩展性高的系统?
  • 处理C10k问题的策略有哪些?
  • 如果让你来设计一个去中心化的P2P系统,你会如何设计?
  • 为什么CGI的扩展性不好?
  • 在设计系统时,你如何防止供应商依赖(Vendor Lock-in)?
  • 在可扩展性上,发布/订阅(Publish-Subscribe)模式有什么缺点?
  • 80年代以后,CPU有哪些变化?这些变化,对编程产生了什么影响?
  • 性能生命周期(performace lifecycle)中,你认为哪个部分是需要考虑进去的? 如何管理?
  • 除了恶意攻击造成的拒绝服务现象以外,哪些设计或者架构上的问题会导致拒绝服务?
  • 性能和可扩展性之间有什么关系?
  • 什么时候紧耦合是OK的?
  • 一个系统要有什么特征才能适配云计算环境(Cloud Ready)?
  • Does unity of design imply an aristocracy of architects?

面向服务架构(SOA)和微服务(Microservice)相关问题:

  • 在SOA中,为什么长期存活的事务(Long-lived transation)不被看好,而Saga却被看好?
  • SOA和MicroService之间有什么区别?
  • 我们来谈谈Web服务的版本管理、版本兼容性、重大变更管理这些事情吧.
  • saga中事务和补偿操作(compensation operation)之间的区别是什么?在SOA中呢?
  • 微服务不能做得太"微",你认为什么时候微服务太"微"了?
  • MicroService架构的优劣是什么?

安全相关问题:

  • 什么是双因素认证(Two Factor Authentication)?在一个已有的Web应用中,你如何实现这种机制?

比尔盖茨式问题:

  • 如果你把一面镜子放在扫描仪上,会发生什么?
  • 假设有一个和你完全一样的克隆人,而他是你的上司,你愿意和他工作吗?
  • 现在请你面试一下我。
  • 为什么Quora上的回答会比Yahoo Answer上的回答好?
  • 对手是现代语言,你的任务是要为Cobol辩护,你会如何进行?
  • 10年后的你是什么样子?
  • 假设你是我老板,我被解雇了。你会如何通知我?
  • 我想要重构一个系统,而你想要从头重写。我们来争论一下该怎么弄吧。然后我们反转角色,再争论一下。
  • 老板要你对公司撒谎,你的反应是什么?
  • 如果你可以穿越到以前,你会给年轻时候的你什么建议?

代码示例问题:

  • 这段Javascript函数的输出是什么?
function hookupevents() {
  for (var i = 0; i < 3; i++) {
    document.getElementById("button" + i)
      .addEventListener("click", function() { 
        alert(i); 
      });
  }
}
  • 关于类型擦除(Type Erasure),这段Java代码的输出是什么?为什么?
ArrayList<Integer> li = new ArrayList<Integer>();
ArrayList<Float> lf = new ArrayList<Float>();
if (li.getClass() == lf.getClass()) // evaluates to true
  System.out.println("Equal");
  • 你能指出哪儿有内存泄漏吗?
public class Stack {
    private Object[] elements;
    private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;

    public Stack() {
        elements = new Object[DEFAULT_INITIAL_CAPACITY];
    }

    public void push(Object e) {
        ensureCapacity();
        elements[size++] = e;
    }

    public Object pop() {
        if (size == 0)
            throw new EmptyStackException();
        return elements[--size];
    }

    /**
     * Ensure space for at least one more element, roughly
     * doubling the capacity each time the array needs to grow.
     */
    private void ensureCapacity() {
        if (elements.length == size)
            elements = Arrays.copyOf(elements, 2 * size + 1);
    }
}
  • if语句,或者更加通用点,条件表达式通常是过程式编程/命令式编程的形式。你能去掉这段代码中的switch语句,用面向对象的方式来修改这段代码吗?
public class Formatter {

    private Service service;

    public Formatter(Service service) {
        this.service = service;
    }

    public String doTheJob(String theInput) {
        String response = service.askForPermission();
        switch (response) {
        case "FAIL":
            return "error";
        case "OK":
            return String.format("%s%s", theInput, theInput);
        default:
            return null;
        }
    }
}
  • 你能去掉这里的if语句,将它改成更加面向对象吗?
public class TheService {
    private final FileHandler fileHandler;
    private final FooRepository fooRepository;

    public TheService(FileHandler fileHandler, FooRepository fooRepository) {
        this.fileHandler = fileHandler;
        this.fooRepository = fooRepository;
    }

    public String Execute(final String file) {

        final String rewrittenUrl = fileHandler.getXmlFileFromFileName(file);
        final String executionId = fileHandler.getExecutionIdFromFileName(file);

        if ((executionId == "") || (rewrittenUrl == "")) {
            return "";
        }

        Foo knownFoo = fooRepository.getFooByXmlFileName(rewrittenUrl);

        if (knownFoo == null) {
            return "";
        }

        return knownFoo.DoThat(file);
    }
}
  • 如何重构这段代码?
function()
{
    HRESULT error = S_OK;

    if(SUCCEEDED(Operation1()))
    {
        if(SUCCEEDED(Operation2()))
        {
            if(SUCCEEDED(Operation3()))
            {
                if(SUCCEEDED(Operation4()))
                {
                }
                else
                {
                    error = OPERATION4FAILED;
                }
            }
            else
            {
                error = OPERATION3FAILED;
            }
        }
        else
        {
            error = OPERATION2FAILED;
        }
    }
    else
    {
        error = OPERATION1FAILED;
    }

    return error;
}
百度 后端工程师

没有假如,我就是一个Golang面试官,来自百度。同时我到百度之前也面过头条,腾讯,小米,高德的golang,基本都过了。我回答应该还是比较有说服力。

事实上,golang的问题只占我面试问题的20%左右。问东西的顺序不一定是下面的顺序,有的时候我会根据简历选择二分法难度来问,直接问一个难度适中的问题。说上来就继续二分法筛。下面是我问过的问题。

1,make和new差别,引用类型的意义

2,逃逸分析

3,channel的实现

4,gmp与gc,重点问题(网络io等待队列,读写屏障)

5,map的实现,重点问题(sync.map的实现,map实现随机的方法)

期间会根据实际情况,从这几个题发散问一些细节,但是难度不会太难了。因为我面的是p6级别的,问源码有点欺负人了。另外会问一个开发性问题,你写go遇到的坑点。从这里也可以发散问一些,但是不会问太多了。这几个问题在10分钟之内肯定要问完的。我的面试范围和我之前遇到过的面试基本都在https://draveness.me/golang/ 内,这个教程还是非常不错的。

这些问题不一定都要答上来,我是综合考察的,我写这几个题目也不是让大家去背这几个题的,只是想告诉大家面试的难度一般如何,顺便说几个经典题目。另外我主要关注的问题其实主要是mysql,redis,mq,算法,分布式。有人看的话,我就补充一下。

——————————————————————————————————————————

9.7 补充mysql

先声明一下,我说的面试题都是个人向的,其实大家要面哪家公司的时候,搜那家公司的面试题用处其实不大,因为面试官并没有说题库,或者统一标准的说法。如果我去了其他家公司当面试官我一样也会这么问(注意是提问方式和难度,题目我会换的)。而你碰到百度其他面试官,也很可能不会按我这么问。另外,因为我面的校招到10年的都有,所以具体问法也会灵活调整。说到校招,这次大校招我也被安排当面试官了,校招的朋友也可以关注一下,如果能答出来,那就惊喜级别

补充一下我对mysql的考察方式。

1,八股,为什么用b+树不用b树

以第一题为分界线,答出来了问下面的

2,说说对mvcc的理解

3,幻读是怎么解决的

4,redo,undo的作用和实现

5,事务的实现

答不出第一题就问,下面就是纯八股了

2,索引怎么建

3,联合索引最左前缀

4,聚簇索引与回表

如果觉得前半部分回答得不行,就会转问后半部分的简单题。和上面一样,我问的问题和我遇见过的问题,基本都在《MySQL技术内幕:InnoDB存储引擎》姜承尧老师的书里面。

——————————————————————————————————————————

9.8 补充redis

redis的东西虽然不多,但是也是必问的。

1,底层数据结构实现,重点问题如:压缩列表

2,aof与rdb,重点问题如:aof重写机制

3,为什么用跳表

4,分布式锁与redlock

5,三种分布式的结构

6,大KEY

基本上说明白一半就行了,和上面一样,我问的问题和我遇见过的问题,大部分都在《Redis设计与实现》里面。因为redis的问题都不算难,如果全答上来了,我可能会问一个:在扩容rehash的时候scan扫集合,会不会扫到重复的数据。

——————————————————————————————————————————

9.9 补充mq+es+分布式

那就补一下剩下的常问问题吧,mq主要是kafka。下面基本上工作3年之内不怎么问,3年以上的说上1/3到1/2就通过。

1,kafka的零拷贝和顺序io 零拷贝最好说说细节,其实就是用户空间和内核空间mmap

2,kafka的分片,分片的读一致性(水位和活跃组?忘了叫什么了)和写一致性怎么保证

3,es的倒排索引,和分片的查询召回

4,分布式锁,redis redlock etcd

5,分布式事务 2pc 3pc tcc

6,分布式共识协议 raft和paxos

7,分布式数据库 CAP BASE的概念 etcd tidb的了解

额外的问题,只有简历写了我才会问

1,k8s的应用和架构(k8s其实我也没深入研究,随便)

2,监控prometheus,比如里面时序数据库TSDB

3,微服务架构的内容,比如服务发现和链路追踪的工具

4,校招的话问问tcp

5,其他我感兴趣的东西

6,算法题必问,一般先选一个中等偏难的,难度参见周赛第三题。要是很顺畅就加一个第四题难度(困难),做不出来就换一个第二题难度(中等偏简单)。

7,架构设计,因为我只是一面,这种问题一般留给二面问。不过我给的建议是,mysql分表,redis缓存,kafka削峰这三板斧

写在最后,其实我的标准只有一个,我的所有提问也是围绕这一标准来的,就是让我感受到你对技术的热情,对技术路线有清晰规划,并且正在进行系统性地有条理的学习持续一年以上,比如看书,事实上我也是这么要求自己的。我相信满足了这个条件,你面其他公司也很容易。

专注分享硬核 Go 语言编程知识,「Go语言入门到精通」作者

[公式]

建议你花 5 钟读完这篇文章,可以帮你节省100% 的寻找答案的时间,一定要坚持读到最后。

收藏的知友记得点个赞,大叔花了不少时间搜集整理,让好东西值得更多人看到。

Go 语言面试题合集

1. 交替打印数字和字母

问题描述

使用两个 goroutine 交替打印序列,一个 goroutine 打印数字, 另外一个 goroutine 打印字母, 最终效果如下:

12AB34CD56EF78GH910IJ1112KL1314MN1516OP1718QR1920ST2122UV2324WX2526YZ2728

解题思路

问题很简单,使用 channel 来控制打印的进度。使用两个 channel ,来分别控制数字和字母的打印序列, 数字打印完成后通过 channel 通知字母打印, 字母打印完成后通知数字打印,然后周而复始的工作。

源码参考

	letter,number := make(chan bool),make(chan bool)
	wait := sync.WaitGroup{}

	go func() {
		i := 1
		for {
			select {
			case <-number:
				fmt.Print(i)
				i++
				fmt.Print(i)
				i++
				letter <- true
			}
		}
	}()
	wait.Add(1)
	go func(wait *sync.WaitGroup) {
		i := 'A'
		for{
			select {
			case <-letter:
				if i >= 'Z' {
					wait.Done()
					return
				}

				fmt.Print(string(i))
				i++
				fmt.Print(string(i))
				i++
				number <- true
			}

		}
	}(&wait)
	number<-true
	wait.Wait()

源码解析

这里用到了两个channel负责通知,letter负责通知打印字母的goroutine来打印字母,number用来通知打印数字的goroutine打印数字。

wait用来等待字母打印完成后退出循环。

2. 判断字符串中字符是否全都不同

问题描述

请实现一个算法,确定一个字符串的所有字符【是否全都不同】。这里我们要求【不允许使用额外的存储结构】。 给定一个string,请返回一个bool值,true代表所有字符全都不同,false代表存在相同的字符。 保证字符串中的字符为【ASCII字符】。字符串的长度小于等于【3000】。

解题思路

这里有几个重点,第一个是ASCII字符ASCII字符字符一共有256个,其中128个是常用字符,可以在键盘上输入。128之后的是键盘上无法找到的。

然后是全部不同,也就是字符串中的字符没有重复的,再次,不准使用额外的储存结构,且字符串小于等于3000。

如果允许其他额外储存结构,这个题目很好做。如果不允许的话,可以使用golang内置的方式实现。

源码参考

通过strings.Count 函数判断:

func isUniqueString(s string) bool {
	if strings.Count(s,"") > 3000{
		return  false
	}
	for _,v := range s {
		if v > 127 {
			return false
		}
		if strings.Count(s,string(v)) > 1 {
			return false
		}
	}
	return true
}

通过strings.Indexstrings.LastIndex函数判断:

func isUniqueString2(s string) bool {
	if strings.Count(s,"") > 3000{
		return  false
	}
	for k,v := range s {
		if v > 127 {
			return false
		}
		if strings.Index(s,string(v)) != k {
			return false
		}
	}
	return true
}

源码解析

以上两种方法都可以实现这个算法。

第一个方法使用的是golang内置方法strings.Count,可以用来判断在一个字符串中包含的另外一个字符串的数量。

第二个方法使用的是golang内置方法strings.Indexstrings.LastIndex,用来判断指定字符串在另外一个字符串的索引未知,分别是第一次发现位置和最后发现位置。

3. 翻转字符串

问题描述

请实现一个算法,在不使用【额外数据结构和储存空间】的情况下,翻转一个给定的字符串(可以使用单个过程变量)。

给定一个string,请返回一个string,为翻转后的字符串。保证字符串的长度小于等于5000。

解题思路

翻转字符串其实是将一个字符串以中间字符为轴,前后翻转,即将str[len]赋值给str[0],将str[0] 赋值 str[len]。

源码参考

func reverString(s string) (string, bool) {
    str := []rune(s)
    l := len(str)
    if l > 5000 {
        return s, false
    }
    for i := 0; i < l/2; i++ {
        str[i], str[l-1-i] = str[l-1-i], str[i]
    }
    return string(str), true
}

4. 判断两个给定的字符串排序后是否一致

问题描述

给定两个字符串,请编写程序,确定其中一个字符串的字符重新排列后,能否变成另一个字符串。 这里规定【大小写为不同字符】,且考虑字符串重点空格。给定一个string s1和一个string s2,请返回一个bool,代表两串是否重新排列后可相同。 保证两串的长度都小于等于5000。

解题思路

首先要保证字符串长度小于5000。之后只需要一次循环遍历s1中的字符在s2是否都存在即可。

源码参考

func isRegroup(s1,s2 string) bool {
	sl1 := len([]rune(s1))
	sl2 := len([]rune(s2))

	if sl1 > 5000 || sl2 > 5000 || sl1 != sl2{
		return false
	}

	for _,v := range s1 {
		if strings.Count(s1,string(v)) != strings.Count(s2,string(v)) {
			return false
		}
	}
	return true
}

源码解析

这里还是使用golang内置方法 strings.Count 来判断字符是否一致。

5. 字符串替换问题

问题描述

请编写一个方法,将字符串中的空格全部替换为“%20”。 假定该字符串有足够的空间存放新增的字符,并且知道字符串的真实长度(小于等于1000),同时保证字符串由【大小写的英文字母组成】。 给定一个string为原始的串,返回替换后的string。

解题思路

两个问题,第一个是只能是英文字母,第二个是替换空格。

源码参考

func replaceBlank(s string) (string, bool) {
	if len([]rune(s)) > 1000 {
		return s, false
	}
	for _, v := range s {
		if string(v) != " " && unicode.IsLetter(v) == false {
			return s, false
		}
	}
	return strings.Replace(s, " ", "%20", -1), true
}

源码解析

这里使用了golang内置方法unicode.IsLetter判断字符是否是字母,之后使用strings.Replace来替换空格。

6. 机器人坐标计算

问题描述

有一个机器人,给一串指令,L左转 R右转,F前进一步,B后退一步,问最后机器人的坐标,最开始,机器人位于 0 0,方向为正Y。 可以输入重复指令n : 比如 R2(LF) 这个等于指令 RLFLF。 问最后机器人的坐标是多少?

解题思路

这里的一个难点是解析重复指令。主要指令解析成功,计算坐标就简单了。

源码参考

package main

import (
	"unicode"
)

const (
	Left = iota
	Top
	Right
	Bottom
)

func main() {
	println(move("R2(LF)", 0, 0, Top))
}

func move(cmd string, x0 int, y0 int, z0 int) (x, y, z int) {
	x, y, z = x0, y0, z0
	repeat := 0
	repeatCmd := ""
	for _, s := range cmd {
		switch {
		case unicode.IsNumber(s):
			repeat = repeat*10 + (int(s) - '0')
		case s == ')':
			for i := 0; i < repeat; i++ {
				x, y, z = move(repeatCmd, x, y, z)
			}
			repeat = 0
			repeatCmd = ""
		case repeat > 0 && s != '(' && s != ')':
			repeatCmd = repeatCmd + string(s)
		case s == 'L':
			z = (z + 1) % 4
		case s == 'R':
			z = (z - 1 + 4) % 4
		case s == 'F':
			switch {
			case z == Left || z == Right:
				x = x - z + 1
			case z == Top || z == Bottom:
				y = y - z + 2
			}
		case s == 'B':
			switch {
			case z == Left || z == Right:
				x = x + z - 1
			case z == Top || z == Bottom:
				y = y + z - 2
			}
		}
	}
	return
}

源码解析

这里使用三个值表示机器人当前的状况,分别是:x表示x坐标,y表示y坐标,z表示当前方向。 L、R 命令会改变值z,F、B命令会改变值x、y。 值x、y的改变还受当前的z值影响。

如果是重复指令,那么将重复次数和重复的指令存起来递归调用即可。

7. 语法题目一

1、下面代码能运行吗?为什么。

type Param map[string]interface{}

type Show struct {
	Param
}

func main1() {
	s := new(Show)
	s.Param["RMB"] = 10000
}

解析

共发现两个问题:

  1. main 函数不能加数字。
  2. new 关键字无法初始化 Show 结构体中的 Param 属性,所以直接对 s.Param 操作会出错。

2、请说出下面代码存在什么问题。

type student struct {
	Name string
}

func zhoujielun(v interface{}) {
	switch msg := v.(type) {
	case *student, student:
		msg.Name
	}
}

解析:

golang中有规定,switch typecase T1,类型列表只有一个,那么v := m.(type)中的v的类型就是T1类型。

如果是case T1, T2,类型列表中有多个,那v的类型还是多对应接口的类型,也就是m的类型。

所以这里msg的类型还是interface{},所以他没有Name这个字段,编译阶段就会报错

8. 语法题目二

由于篇幅有限制,需要相关面试题解析的读者

大家可以直接查阅大叔整理的这本面试电子书。

9. goroutine和channel使用一

10. 实现阻塞读的并发安全Map

11. 高并发下的锁与map读写问题

12. 定时与 panic 恢复

13. 为 sync.WaitGroup 中Wait函数支持 WaitTimeout 功能.

14. golang 并发题目测试

15. 记一道字节跳动的算法面试题

16. 多协程查询切片问题

17. 对已经关闭的的chan进行读写,会怎么样?为什么?

18. 简单聊聊内存逃逸?

19. 字符串转成byte数组,会发生内存拷贝吗?

20. http包的内存泄漏

21. sync.Map 的用法

22. Go语言的GPM调度器是什么?

23. Goroutine调度策略

24. goroutine调度器概述

Redis基础

1. Redis 基础数据结构

2. Redis中的底层数据结构

3. Redis持久化的原理及优化

4. Redis中内存淘汰算法实现

5. Redis主从复制原理

MySQL相关

1. MySQL数据库经典面试题解析

2. MySQL InnoDB MVCC 机制的原理及实现

3. 为什么MySQL使用B+树做索引?

Golang面试必备算法

1. 字符串之实现 Sunday 匹配

2. 字符串泄漏之反转字符串(301)

3. 字符串中的第一个唯一字符

4. 字符串之验证回文串

5. 滑动窗口最大值

6. 最长公共前缀

7. 两个数组的交集

8. 最接近的三数之和

9. 排序算法

10. 冒泡排序

11. 选择排序

Go 语言电子书推荐

Go语言学习指南链接 提取码:dmqx

Go-Web编程百度云链接:提取码:ty2c

Go并发实战链接:提取码:41zd

Go语言编程链接 提取码:dcu3

Go语言标准库链接:提取码:8kx9

Go语言程序设计:提取码:2uqt

Go语言圣经:提取码:7emu

Go语言实战:提取码:f7o2

Go语言学习笔记:提取码:7il3

Go 语言学习路线图(2021版)

项目地址:https://github.com/coderit666/GoGuide

除了 Go 语言学习指南这张路线图之外,大叔再 GitHub 上寻找到了第 2 张 Go 语言学习路线图,目前被广大 Golang 爱好者,它是 Golang 学习路线图 2021 版本,非常新。

项目地址:https://github.com/Alikhll/golang-developer-roadmap/blob/master/i18n/zh-CN/ReadMe-zh-CN.md

最后,避免你学习踩坑,大叔将自己整理的学习踩坑建议分享与你,助力你能少走一些弯路。

Go 语言学习建议

不要通过共享内存进行通信,通过通信共享内存
并发不是并行
管道用于协调;互斥量(锁)用于同步
接口越大,抽象就越弱
利用好零值
空接口 interface{} 没有任何类型约束
Gofmt 的风格不是人们最喜欢的,但 gofmt 是每个人的最爱
允许一点点重复比引入一点点依赖更好
系统调用必须始终使用构建标记进行保护
必须始终使用构建标记保护 Cgo
Cgo 不是 Go
使用标准库的 unsafe 包,不能保证能如期运行
清晰比聪明更好
反射永远不清晰
错误是值
不要只检查错误,还要优雅地处理它们
设计架构,命名组件,(文档)记录细节
文档是供用户使用的
不要(在生产环境)使用 panic()
每个 package 实现单一的目的
显式处理错误
尽早返回,而不是使用深嵌套
让调用者处理并发(带来的问题)
在启动一个 goroutine 时,需要知道何时它会停止
避免 package 级别的状态
简单很重要
编写测试以锁定 package API 的行为
如果你觉得慢,先编写 benchmark 来证明
适度是一种美德
可维护性

最后,如果觉得大叔的分享对你有帮助,欢迎关注我

我是大叔,一个擅长 Go 语言、互联网 Offer 选择、离职交接问题的码农

 欢迎与我深度链接,一起成长。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK