爬虫遇到了点问题

golang爬珍爱网代码优化后,运行报了如下的错,找了半小时才找到原因,在此记录一下。

代码是这样的:

有一个interface类型的Parser:

type Parser interface {
   Parser(contents []byte, url string) ParserResult
   Serialize() (funcName string, args interface{})
}

有一个struct类型的FuncParser:

type FuncParser struct {
   parser ParserFunc
   funcName string
}

FuncParser 实现了Parser 接口:

func (f *FuncParser) Parser(contents []byte, url string) ParserResult {
   return f.Parser(contents, url)
}

func (f *FuncParser) Serialize() (funcName string, args interface{}) {
   return f.funcName, nil
}

抛开爬虫代码整体的复杂度,将代码简化到如下这样:

type ParserFunc func(url string) string

type FuncParser struct {
    parser ParserFunc
}

func (f *FuncParser) Parser(url string) string {
    return f.Parser(url)
}

func main() {

    funcParse := FuncParser{
        func(url string) string {
            return url
        },
    }

    funcParse.Parser("http://www.zhenai.com/zhenghun")
}

运行代码后同样会报错:

runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow

runtime stack:
runtime.throw(0x467297, 0xe)
    D:/Program Files/Go/go103/src/runtime/panic.go:616 +0x88
runtime.newstack()
    D:/Program Files/Go/go103/src/runtime/stack.go:1054 +0x72d
runtime.morestack()
    D:/Program Files/Go/go103/src/runtime/asm_amd64.s:480 +0x91

这个示例就很明显了,FuncParser的Parser方法里形成了递归调用(自己调自己),递归调用自身导致栈溢出,导致报错。应该改成这样:(小写的parser)

实际上goland开发工具里已经提示了Recursive Call


一不小心就会写出这种代码,再看如下代码:

package main

import (
    "fmt"
)

type Str string

func (s Str) String() string {
    return fmt.Sprintf("Str: %s", s)
}

func main() {
    var s Str = "hi"
    fmt.Println(s)
}

同样报错:

You are implementing Str.String in terms of itself. return fmt.Sprintf("Str: %s", s) will call s.String(), resulting in infinite recursion. Convert s to string first.

This is working as intended, you are using the %s verb to call Str's String method, which uses fmt.Sprint to call Str's String method, and so on.

正常代码应该如下:

实际上,goland开发工具里也会警告该问题的:

看来平时编写代码,警告还是得注意的。

项目代码见:https://github.com/ll837448792/crawler

原文发布于微信公众号 - 我的小碗汤(mysmallsoup)

原文发表时间:2018-09-01

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏高爽的专栏

Nested-Loop Join Algorithms

MySQL使用嵌套循环算法来实现多表之间的联接。 Nested-Loop Join Algorithms 一个简单的嵌套循环联接(NLJ)算法,循环从第一个表中...

26600
来自专栏技术之路

【swift学习笔记】五.使用枚举优雅的管理Segue

  在做页面转跳的时候,我们要给Segue命名,如果Segue多了,管理他们就是一个恶梦。我们可以枚举更优雅的管理这些Segue。   1.我们先来建立一个pr...

17650
来自专栏张善友的专栏

ASP.NET SignalR HubPipelineModule

ASP.NET SignalR 1.0 实现的一个特性HubPipeline -实现任何消息incoming和outgoing的拦截。SignalR HubPi...

22970
来自专栏清晨我上码

第九节 netty前传-NIO 补充Path和File

Java NIO.Path接口位于java.nio.file包中,所以Java Path接口的完全限定名称是java.nio.file.Path。

11340
来自专栏跟着阿笨一起玩NET

.NET深入解析LINQ框架(六:LINQ执行表达式)

在看本篇文章之前我假设您已经具备我之前分析的一些原理知识,因为这章所要讲的内容是建立在之前的一系列知识点之上的,为了保证您的阅读顺利建议您先阅读本人的LINQ系...

7310
来自专栏哈雷彗星撞地球

RunLoop总结:RunLoop 与GCD 、Autorelease Pool之间的关系

如果在面试中问到RunLoop相关的知识,很有可能也会问到RunLoop与GCD、Autorelease Pool有没有关系,哪些地方用到了GCD、Autore...

11040
来自专栏程序员的SOD蜜

.net访问PostgreSQL数据库发生“找不到函数名”的问题追踪

    PostgreSQL是一个使用广泛的免费开源的数据库,与MySQL比较,它更适合复杂的企业计算任务,而MySQL在互联网领域应用更为广泛,究其原因,可能...

37670
来自专栏WindCoder

java基于SSM的Quartz计划任务配置

想找下Quartz的资料看下,某度,随之眼瞎,你们copy就算了,就不能用心点么,连个代码高亮都不忍心加,实在没心情看下去,但还是要忍一下,待我整理完整,再也不...

33410
来自专栏aCloudDeveloper

MessageBeep - Play a System sound

There is a interesting function which can play a System sound. First let's see t...

19880
来自专栏林德熙的博客

C# 字典 Dictionary 的 TryGetValue 与先判断 ContainsKey 然后 Get 的性能对比

本文使用 benchmarkdotnet 测试字典的性能,在使用字典获取一个可能存在的值的时候可以使用两个不同的写法,于是本文分析两个写法的性能。

2.4K20

扫码关注云+社区

领取腾讯云代金券